Skip to content

Commit

Permalink
gh-156: Support loop_factory parameter in bench_async_func (gh-157)
Browse files Browse the repository at this point in the history
  • Loading branch information
itamaro authored Mar 23, 2023
1 parent d5349bb commit 989d38f
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 11 deletions.
5 changes: 4 additions & 1 deletion doc/api.rst
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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

0 comments on commit 989d38f

Please sign in to comment.