Skip to content
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

Support loop_factory parameter in bench_async_func #157

Merged
merged 2 commits into from Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion doc/api.rst
Expand Up @@ -539,7 +539,7 @@ Runner class

See the :ref:`bench_func() example <bench_func_example>`.

.. method:: bench_async_func(name, func, \*args, inner_loops=None, metadata=None)
.. method:: bench_async_func(name, func, \*args, inner_loops=None, metadata=None, loop_factory=None)

Benchmark the function ``await func(*args)`` in asyncio event loop.

Expand All @@ -548,6 +548,9 @@ Runner class
The *inner_loops* parameter is used to normalize timing per loop
iteration.

The *loop_factory* parameter, if specified, will be used to create the
event loop used by the benchmark.

To call ``func()`` with keyword arguments, use ``functools.partial``.

Return a :class:`Benchmark` instance.
Expand Down
5 changes: 4 additions & 1 deletion doc/changelog.rst
@@ -1,12 +1,15 @@
Changelog
=========

Version 2.6.0 (2022-11-21)
Version 2.6.0 (2023-03-22)
--------------------------

* Inherit ``PYTHONPATH`` environment variable by default.
Patch by Theodore Ni.

* ``Runner.bench_async_func()`` takes an optional ``loop_factory`` to support custom loop construction.
Patch by Itamar O.

Version 2.5.0 (2022-11-04)
--------------------------

Expand Down
15 changes: 15 additions & 0 deletions doc/examples/bench_async_func_with_loop_factory.py
@@ -0,0 +1,15 @@
#!/usr/bin/env python3
import asyncio
import pyperf


def loop_factory():
return asyncio.new_event_loop()


async def func():
await asyncio.sleep(0.001)


runner = pyperf.Runner()
runner.bench_async_func('async_sleep', func, loop_factory=loop_factory)
23 changes: 14 additions & 9 deletions pyperf/_runner.py
Expand Up @@ -546,6 +546,7 @@ def bench_async_func(self, name, func, *args, **kwargs):

inner_loops = kwargs.pop('inner_loops', None)
metadata = kwargs.pop('metadata', None)
loop_factory = kwargs.pop('loop_factory', None)
self._no_keyword_argument(kwargs)

if not self._check_worker_task():
Expand Down Expand Up @@ -582,16 +583,20 @@ async def main():
return dt

import asyncio
if hasattr(asyncio, 'run'): # Python 3.7+
dt = asyncio.run(main())
else: # Python 3.6
# using the lower level loop API instead of asyncio.run because
# asyncio.run gained the `loop_factory` arg only in Python 3.12.
# we can go back to asyncio.run when Python 3.12 is the oldest
# supported version for pyperf.
if loop_factory is None:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
dt = loop.run_until_complete(main())
finally:
asyncio.set_event_loop(None)
loop.close()
else:
loop = loop_factory()
asyncio.set_event_loop(loop)
try:
dt = loop.run_until_complete(main())
finally:
asyncio.set_event_loop(None)
loop.close()

return dt

Expand Down
6 changes: 6 additions & 0 deletions pyperf/tests/test_examples.py
Expand Up @@ -52,6 +52,12 @@ def test_bench_async_func(self):
args = ['-p2', '-w1', '--min-time=0.001']
self.check_command(script, args)

def test_bench_async_func_with_loop_factory(self):
script = 'bench_async_func_with_loop_factory.py'
# Use -w1 --min-time=0.001 to reduce the duration of the test
args = ['-p2', '-w1', '--min-time=0.001']
self.check_command(script, args)

def test_bench_time_func(self):
script = 'bench_time_func.py'
args = ['-p2', '-w1', '--min-time=0.001']
Expand Down