Page 1 of 1
Slow returning scalar types in async function
Posted: Fri Feb 25, 2022 2:59 am
by yjchun
I found a weird performance issue. In async functions, it is a lot slower when returning scalar types than object types.
Code: Select all
import time
import uasyncio as asyncio
async def ret(arg):
return arg
async def test3(count=10000, d=False):
for n in range(count):
if d:
v = dict() # list() or object()
else:
v = 0 # True 0.0 int() str()
await ret(v)
t = time.ticks_ms()
asyncio.run(test3(d=True))
print('dict(): ' + str(time.ticks_diff(time.ticks_ms(), t)))
t = time.ticks_ms()
asyncio.run(test3(d=False))
print('int: ' + str(time.ticks_diff(time.ticks_ms(), t)))
in RP2:
dict(): 427
int: 3556
in unix:
dict(): 4
int: 157
in CPython:
dict(): 4
int: 3
Tested with yesterday's master.
I am a heavy user of asyncio and when I wanted to optimize my code by using simple types rather than creating objects, the result was the opposite. Anyone have any clue?
Thanks.
Re: Slow returning scalar types in async function
Posted: Fri Feb 25, 2022 8:57 am
by yjchun
Similar result with yield:
Code: Select all
import time
def ret(arg):
yield arg
def test3(count=10000, d=False):
for n in range(count):
if d:
v = dict(a=0) # list() object()
else:
v = int() # 0
r = next(ret(v))
t = time.ticks_ms()
test3(d=True)
print('dict(): ' + str(time.ticks_diff(time.ticks_ms(), t)))
t = time.ticks_ms()
test3(d=False)
print('int: ' + str(time.ticks_diff(time.ticks_ms(), t)))
with unix micropython:
dict(): 7
int: 90
with CPython:
dict(): 5
int: 5
Re: Slow returning scalar types in async function
Posted: Fri Feb 25, 2022 11:56 am
by pythoncoder
This is puzzling. I repeated the test with synchronous code:
Code: Select all
import time
def ret(arg):
return arg
def test3(count=10000, d=False):
for n in range(count):
if d:
v = {} # faster than dict()
else:
v = 0
ret(v)
t = time.ticks_ms()
test3(d=True)
print('dict(): ' + str(time.ticks_diff(time.ticks_ms(), t)))
t = time.ticks_ms()
test3(d=False)
print('int: ' + str(time.ticks_diff(time.ticks_ms(), t)))
with the outcome (on a Pico)
For some reason assigning an
int seems much slower in a coroutine than in synchronous code. This is particularly odd as in your benchmark I don't think the scheduler ever gets a look-in. However if I add a
asyncio.sleep_ms(0) in
ret() there is still a >2:1 discrepancy in favour of the dict:
Re: Slow returning scalar types in async function
Posted: Fri Feb 25, 2022 6:34 pm
by yjchun
Code: Select all
import time
def ret(arg):
yield None
def test3(klass=int, count=10000):
for n in range(count):
v = klass()
ret(v)
def test4(v=0, count=10000):
for n in range(count):
ret(v)
t = time.ticks_ms()
test3(dict)
print('dict(): ' + str(time.ticks_diff(time.ticks_ms(), t)))
t = time.ticks_ms()
test3(int)
print('int: ' + str(time.ticks_diff(time.ticks_ms(), t)))
t = time.ticks_ms()
test4()
print('test4: ' + str(time.ticks_diff(time.ticks_ms(), t)))
dict(): 391
int: 4874
test4: 5013
Further narrowed down the problem. And I don't understand the results.
Not only the problem is passing value to a generator function but also it matters type of value and location of value definition.
test4() is supposed to be fastest because new object is not created but it is the slowest. And that 10 times slower...
Re: Slow returning scalar types in async function
Posted: Sat Feb 26, 2022 1:39 pm
by pythoncoder
The code
is running a generator function, instantiating a generator, and then discarding the generator. This is an unusual thing to do in a loop. While your observation is very odd, I'm not sure whether the performance of a generator function (rather than a generator) would be seen as a critical bug.
Re: Slow returning scalar types in async function
Posted: Sat Feb 26, 2022 2:57 pm
by yjchun
pythoncoder wrote: ↑Sat Feb 26, 2022 1:39 pm
The code
is running a generator function, instantiating a generator, and then discarding the generator. This is an unusual thing to do in a loop. While your observation is very odd, I'm not sure whether the performance of a generator function (rather than a generator) would be seen as a critical bug.
Hello @pythoncoder. Yes I know that. I wanted to show the performance problem of asyncio and that instantiating generator is the source of performance issue. If I understand correctly, everytime async function is called, a generator function is created(instantiated).
Re: Slow returning scalar types in async function
Posted: Sun Feb 27, 2022 8:27 am
by stijn
Something is very wrong here. Windows port for test3 (and 10 iterations of that just to make sure):
Code: Select all
dict 15.809
int 3406.55
float 22.054
Seems worth creating a Github issue for this: while it's not suprirising creating a generator has an overhead, the differences observed here are so large it's either an underlying problem, or at least wordt being documented somewhere.
Re: Slow returning scalar types in async function
Posted: Mon Feb 28, 2022 8:38 am
by stijn