From f9a76df2f14758952d26ff23bb980725697060ee Mon Sep 17 00:00:00 2001 From: Ciro Date: Wed, 8 Feb 2023 15:53:52 -0300 Subject: [PATCH] async 10 to 20% faster --- bench/asgi_wsgi/raw-asgi.py | 2 +- src/socketify/asgi.py | 12 +++++------- src/socketify/loop.py | 10 ++++------ src/socketify/tasks.py | 6 ++++-- src/socketify/wsgi.py | 11 ++++++----- 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/bench/asgi_wsgi/raw-asgi.py b/bench/asgi_wsgi/raw-asgi.py index ae8355c..43c19f8 100644 --- a/bench/asgi_wsgi/raw-asgi.py +++ b/bench/asgi_wsgi/raw-asgi.py @@ -20,4 +20,4 @@ async def app(scope, receive, send): if __name__ == "__main__": - ASGI(app).listen(8000, lambda config: print(f"Listening on port http://localhost:{config.port} now\n")).run(8) + ASGI(app, lifespan=False).listen(8000, lambda config: print(f"Listening on port http://localhost:{config.port} now\n")).run(8) diff --git a/src/socketify/asgi.py b/src/socketify/asgi.py index 6e8888b..9af72f3 100644 --- a/src/socketify/asgi.py +++ b/src/socketify/asgi.py @@ -533,7 +533,8 @@ class _ASGI: else: def run_task(task): - create_task(loop, task_wrapper(task)) + future = create_task(loop, task_wrapper(task)) + future._log_destroy_pending = False loop._run_once() self._run_task = run_task @@ -542,19 +543,16 @@ class _ASGI: if sys.version_info >= (3, 8): # name fixed to avoid dynamic name def run_task(task): - future = loop.create_task( - task_wrapper(task), name="socketify.py-request-task" - ) + future = create_task(loop, task_wrapper(task)) + future._log_destroy_pending = False - loop._run_once() self._run_task = run_task else: def run_task(task): - future = loop.create_task(task_wrapper(task)) + future = create_task(loop, task_wrapper(task)) future._log_destroy_pending = False - loop._run_once() self._run_task = run_task diff --git a/src/socketify/loop.py b/src/socketify/loop.py index d5bd3a7..1d33836 100644 --- a/src/socketify/loop.py +++ b/src/socketify/loop.py @@ -129,18 +129,16 @@ class Loop: future = self._task_factory( self.loop, task_wrapper(self.exception_handler, self.loop, response, task) ) - # force asyncio run once to enable req in async functions before first await + # this call makes pypy 10% to 20% faster in async, but will work without it + # this also makes uvloop incompatible if uvloop becomes compatible with pypy self.loop._run_once() return None # this future maybe already done and reused not safe to await def _run_async_cpython(self, task, response=None): # this garanties error 500 in case of uncaught exceptions, and can trigger the custom error handler # using an coroutine wrapper generates less overhead than using add_done_callback - future = self.loop.create_task( - task_wrapper(self.exception_handler, self.loop, response, task) - ) - # force asyncio run once to enable req in async functions before first await - self.loop._run_once() + # custom task will call _step, reusing tasks in CPython is not worth + future = create_task(self.loop, task_wrapper(self.exception_handler, self.loop, response, task)) return None # this future is safe to await but we return None for compatibility, and in the future will be the same behavior as PyPy def dispose(self): diff --git a/src/socketify/tasks.py b/src/socketify/tasks.py index e566dc8..e6f69fe 100644 --- a/src/socketify/tasks.py +++ b/src/socketify/tasks.py @@ -115,7 +115,8 @@ class RequestTask: self._log_destroy_pending = False if self._loop.get_debug(): self._source_traceback = format_helpers.extract_stack(sys._getframe(1)) - self._loop.call_soon(self.__step, context=self._context) + # self._loop.call_soon(self.__step, context=self._context) + self.__step() _register_task(self) def _reuse(self, coro, loop, default_done_callback=None): @@ -147,7 +148,8 @@ class RequestTask: self._fut_waiter = None self._coro = coro - self._loop.call_soon(self.__step, context=self._context) + # self._loop.call_soon(self.__step, context=self._context) + self.__step() _register_task(self) def __repr__(self): diff --git a/src/socketify/wsgi.py b/src/socketify/wsgi.py index b3022e0..c0b2605 100644 --- a/src/socketify/wsgi.py +++ b/src/socketify/wsgi.py @@ -361,7 +361,8 @@ class _WSGI: else: def run_task(task): - create_task(loop, task) + future = create_task(loop, task) + future._log_destroy_pending = False loop._run_once() self._run_task = run_task @@ -370,15 +371,15 @@ class _WSGI: if sys.version_info >= (3, 8): # name fixed to avoid dynamic name def run_task(task): - loop.create_task(task, name="socketify.py-request-task") - loop._run_once() + future = create_task(loop, task) + future._log_destroy_pending = False self._run_task = run_task else: def run_task(task): - loop.create_task(task) - loop._run_once() + future = create_task(loop, task) + future._log_destroy_pending = False self._run_task = run_task