-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
timeit support for coroutines #121
Comments
@vstinner Do you have any ideas? |
I don't know how to do that. cc @methane |
@Tinche Do you really mean
|
Would you give us some examples? |
I use Here's an example. I have a project, https://github.com/Tinche/incant/, that does function composition (mostly for dependency injection), and I want to measure how efficient it is. It supports functions and coroutines. Functions I can benchmark easily, coroutines I need to benchmark using Note that these coroutines I'm benchmarking are technically async, but they either do not await anything or they await I usually prepare the function being tested in a file and then do something like:
so since I need to have a separate file That said, maybe there's a way to run a coroutine without involving an event loop? Just iterate over it until it's done or something like that? I'm not proficient in that part of Python. |
Would you try this? pyperf timeit -g -s "import asyncio; loop=asyncio.get_event_loop(); from test import main" \
"loop.run_until_complete(main())" or pyperf timeit -g -s "import asyncio, test" \
"asyncio.get_event_loop().run_until_complete(test.main())" With this, one loop is used repeatedly instead of creating and destroying loops for each main() execution. |
It does work and helps a little. If it's too hard to do otherwise in pyperf I will accept this as the answer ;) |
What "little" means? It reduce your noise only little? If so, it means this feature request will have only little benefit. If you just meant "I don't want to write this timeit", I'm sorry. But it is very difficult. I will consider about adding |
Well, it reduces the running time by a lot, so it reduces noise by a lot. I have a generated coroutine that that I'm benchmarking. This coroutine awaits several other coroutines inside.
So the difference was noise introduced by |
Offtopic: heh, for comparison's sake, if I change the test so they are all ordinary functions, not async def functions, it takes 1 microsecond. I wasn't aware asyncio/the event loop adds so much overhead. |
Each call to asyncio.run() creates a new fresh event loop, and then closes it. Moreover, it also shutdowns asynchronous generators and the default asyncio executor (thread pool). |
Since you write script for test already, I don't think timeit command is so important for you. if __name__ == '__main__':
import pyperf
pyperf.Runner().bench_async_func('main', main) |
@methane Thanks a lot! Trying from your branch, now the time is: |
I closed the issue because it seems like the idea of adding an |
I was curious and compared
Using an asyncio sleep of 1 ms, there is no significant difference: for me, it confirms that the pyperf implementation is correct ;-) The accuracy is good. We don't measure the time spent to create and close the event loop. |
(A) Benchmark on asyncio.run() with bench_func() on a coroutine func() which does nothing:
(B) Benchmark on loop.run_until_complete(loop) with bench_func() on a coroutine func() which does nothing:
(C) Benchmark pyperf 2.3.1 new bench_async_func() method on a coroutine func() which does nothing:
Results on Python 3.10:
The std dev is way better using bench_async_func()!
|
I don't think that detecting if the argument looks like a coroutine or not is not a good idea. It requires to |
This function is now part of the just released pyperf 2.3.1. |
Hello!
I think
pyperf
is an amazing project and I use thetimeit
to benchmark essentially all the libraries I work on (attrs, cattrs, incant...).I wish I could use it to benchmark async functions though. Right now, I benchmark
asyncio.run(my_coro)
but sinceasyncio.run
is so costly there's a ton of noise in the signal.I think essentially pyperf could detect a coroutine was passed in, spawn an event loop and just await it in a loop.
The text was updated successfully, but these errors were encountered: