From af3cb343a4f80180725350723e94851dbf55ff05 Mon Sep 17 00:00:00 2001 From: Pau Freixes Date: Thu, 28 Dec 2017 18:01:20 +0100 Subject: [PATCH] Skip middleware code when there are no user middlewares installed (#2629) * Skip middleware code when there are no user middlewares installed Fixes performance issue introduced by #2577, boosting from 8K req/sec to almost 9K req/sec. If there are no middlewares installed by the user the attribute `request._match_info.current_app` already looks at to the right app, this is by design. --- CHANGES/2629.feature | 1 + aiohttp/web_app.py | 27 ++++++++++++++++++++------- tests/test_web_app.py | 26 ++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 CHANGES/2629.feature diff --git a/CHANGES/2629.feature b/CHANGES/2629.feature new file mode 100644 index 00000000000..dc187a37cbe --- /dev/null +++ b/CHANGES/2629.feature @@ -0,0 +1 @@ +Fixes performance issue introduced by #2577. When there are no middlewares installed by the user, no additional and useless code is executed. diff --git a/aiohttp/web_app.py b/aiohttp/web_app.py index 304f0c15168..944316e93bd 100644 --- a/aiohttp/web_app.py +++ b/aiohttp/web_app.py @@ -110,15 +110,25 @@ def freeze(self): return self._frozen = True - self._middlewares = tuple(self._prepare_middleware()) + self._middlewares.freeze() self._router.freeze() self._on_response_prepare.freeze() self._on_startup.freeze() self._on_shutdown.freeze() self._on_cleanup.freeze() + self._middlewares_handlers = tuple(self._prepare_middleware()) + + # If current app and any subapp do not have middlewares avoid run all + # of the code footprint that it implies, which have a middleware + # hardcoded per app that sets up the current_app attribute. If no + # middlewares are configured the handler will receive the proper + # current_app without needing all of this code. + self._run_middlewares = True if self.middlewares else False for subapp in self._subapps: subapp.freeze() + self._run_middlewares =\ + self._run_middlewares or subapp._run_middlewares @property def debug(self): @@ -241,6 +251,7 @@ def _prepare_middleware(self): 'see #2252'.format(m), DeprecationWarning, stacklevel=2) yield m, False + yield _fix_request_current_app(self), True async def _handle(self, request): @@ -260,12 +271,14 @@ async def _handle(self, request): if resp is None: handler = match_info.handler - for app in match_info.apps[::-1]: - for m, new_style in app._middlewares: - if new_style: - handler = partial(m, handler=handler) - else: - handler = await m(app, handler) + + if self._run_middlewares: + for app in match_info.apps[::-1]: + for m, new_style in app._middlewares_handlers: + if new_style: + handler = partial(m, handler=handler) + else: + handler = await m(app, handler) resp = await handler(request) diff --git a/tests/test_web_app.py b/tests/test_web_app.py index 3f020cba7bf..df0313aa2ce 100644 --- a/tests/test_web_app.py +++ b/tests/test_web_app.py @@ -195,6 +195,7 @@ def test_app_delitem(): def test_app_freeze(): app = web.Application() subapp = mock.Mock() + subapp._middlewares = () app._subapps.append(subapp) app.freeze() @@ -210,3 +211,28 @@ def test_equality(): assert app1 == app1 assert app1 != app2 + + +def test_app_run_middlewares(): + + root = web.Application() + sub = web.Application() + root.add_subapp('/sub', sub) + root.freeze() + assert root._run_middlewares is False + + @web.middleware + async def middleware(request, handler): + return await handler(request) + + root = web.Application(middlewares=[middleware]) + sub = web.Application() + root.add_subapp('/sub', sub) + root.freeze() + assert root._run_middlewares is True + + root = web.Application() + sub = web.Application(middlewares=[middleware]) + root.add_subapp('/sub', sub) + root.freeze() + assert root._run_middlewares is True