-
-
Notifications
You must be signed in to change notification settings - Fork 31.8k
Audit asyncio thread safety #128002
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
Comments
You may be already planning on this, but I think it'd be helpful to have a summary of the current thread safety issues in these classes and functions. |
I have gathered data of performance of pure python implementation and C implementation. Without free-threading
With free-threading
From this data, it looks like there's on average slowdown of 1.50x when disabling the C implementation as such it is too large of performance loss to consider dropping the C implementation even in case of free-threading. Some thread safety Issues in C implementationHere's an outline of some of the thread safety issues, I'll be adding more to this list.
Performance bottlenecks in free-threadingConsider an async server which uses multiple threads to run one independent loop per thread.
|
I vaguely remember past discussions about moving the global state to live on the loop. I don't remember what was the conclusion (or if there was a conclusion), but if we do that, that would resolve most thread-safety issues, wouldn't it? |
That has backwards compatibility issues with custom event loops, currently asyncio handles it for all loops. Moving things to event loop may improve performance for free-threading but will causes performance loss in normal builds and in cases where just a single loop runs because of extra attribute lookups and indirection and we cannot use non-python data structures like the new double linked-lists implementation. |
* Makes `_asyncio.Task` and `_asyncio.Future` thread-safe by adding critical sections * Add assertions to check for thread safety checking locking of object by critical sections in internal functions * Make `_asyncio.all_tasks` thread safe when eager tasks are used * Add a thread safety test
@kumaraditya303 - I think we're missing a |
So I think that would be the case when
I have a side question: judging from the function name |
Yes. In that case, I think
It's called on objects when weakrefs are actually created. Most objects that are weakrefable do not actually have any weakrefs. |
That makes sense, created #128885 to fix this. |
Co-authored-by: Łukasz Langa <[email protected]>
…#128869) Co-authored-by: Łukasz Langa <[email protected]>
…#128869) Co-authored-by: Łukasz Langa <[email protected]>
…d of manual iteration (#129942)
Currently, lazy executionWith #128869, lazy tasks use per thread linked list of tasks so in the general case there should be no contention around registering and unregistering of tasks. eager executionCurrently, There are a few ways to improve performance under free-threading when eager execution I can think of:
I am leaning towards the second approach as it will be most performant and lock free in the general case but I would like to hear from @itamaro as I think Instagram currently uses eager execution by default so they would know more. Also @colesbury for any alternatives for better performance in free-threading that I might have missed. Footnotes
|
The second approach would also make it much easier for external introspection to inspect eager tasks cc @ambv @pablogsal |
The second approach sounds reasonable to me! In cinder 3.10, I think all native tasks (eager and lazy) are stored in one linked list. |
I created #130518 to store eager tasks in the same linked list as lazy tasks, it is much simpler and less changes are required. |
The following functions needs to be made thread safe and atomic for free-threading for both pure python and C implementation:
asyncio._enter_task
asyncio._leave_task
asyncio._register_task
asyncio._unregister_task
asyncio._swap_current_task
asyncio.current_task
asyncio.all_tasks
Note that some of these were made thread safe in C impl #120974
The following classes needs to be thread safe for free-threading in C implementation:
asyncio.Task
asyncio.Future
Both of these classes are documented to be not thread safe but currently calling methods on these classes from multiple threads can crash the interpreter. The pure python implementation cannot crash the interpreter when called from multiple threads so changes are only needed for C implementation. Before making these thread safe in C I would gather some numbers for how much a difference the C implementation makes in free-threading and if it isn't much we can just disable the C extension for free-threading.
cc @colesbury
Linked PRs
asyncio.all_tasks
against concurrent deallocations of tasks #128541_PyObject_SetMaybeWeakref
when creating tasks in asyncio #128885test_all_tasks_different_thread
in asyncio #129267PyList_Extend
instead of manual iteration #129942asyncio.all_tasks
#129943The text was updated successfully, but these errors were encountered: