Speed up Local#551
Conversation
|
I have seen Local show up in profiles as well, and I don't even use async, so it'd be great to have its performance improved. I wonder given that |
Sure. Triplicating the logic into the functions would probably make a lot of sense for performance, but those functions should probably be comment-marked "there be dragons here, be very careful" 😄 |
|
@bluetech Great news: according to my measurements it is indeed a whole lot faster, another +100% on top of the context-manager version 😄 |
Thanks to bluetech for the idea.
|
Gentle review nudge, @carltongibson? 😄 (Ditto for #552) |
|
@akx Nice 😃 — I'm just working my way back to asgiref now, as it happens. 🎁 |
While profiling a Django app with viztracer, I noticed
asgirefLocal access/locking being actually visible in the trace, and figured there could be something to fix perf-wise :)@contextlib.contextmanagercan be slow due to the fact that the interpreter needs to juggle a generator frame, etc.This PR replaces it with a small real context manager (that is stored on the instance for reuse instead, in the first commit.The second commit further specializes
Local(using__new__magic, so this is transparent to consumers) to 2 classes depending on ifthread_criticalis set, so accesses do not require branches at all – and indeed, in the thread-critical case,nullcontextisn't required anymore. (Further, the guards in thesetattrcase become unnecessary since we can just useobject.__setattr__to sidestep the classes' impls.)EDIT: the third commit gets rid of the context manager altogether in favor of just inlining the same things as a
try:finally:block, as per comments here, for even more performance. 😄I pytest-benchmarked this to be pleasantly faster (and given that these are often very hot paths in Django, this is a nice win for not an awful lot of additional code):
Real context manager
test_getattr_thread_criticaltest_setattr_thread_criticaltest_getattr_defaulttest_setattr_defaulttest_delattr_thread_criticaltest_getattr_missing_defaulttest_delattr_defaulttest_getattr_thread_critical_asynctest_setattr_thread_critical_asyncNo context manager (only affects
default)