mirror of
https://github.com/python/cpython.git
synced 2025-12-23 09:19:18 +00:00
gh-140414: add fastpath for current running loop in asyncio.all_tasks (#140542)
Some checks are pending
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / Windows MSI (push) Blocked by required conditions
Tests / (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / Sanitizers (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / Ubuntu SSL tests with AWS-LC (push) Blocked by required conditions
Tests / Android (aarch64) (push) Blocked by required conditions
Tests / Android (x86_64) (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / Cross build Linux (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Lint / lint (push) Waiting to run
mypy / Run mypy on Lib/tomllib (push) Waiting to run
mypy / Run mypy on Lib/_pyrepl (push) Waiting to run
mypy / Run mypy on Lib/test/libregrtest (push) Waiting to run
mypy / Run mypy on Tools/build (push) Waiting to run
mypy / Run mypy on Tools/cases_generator (push) Waiting to run
mypy / Run mypy on Tools/clinic (push) Waiting to run
mypy / Run mypy on Tools/jit (push) Waiting to run
mypy / Run mypy on Tools/peg_generator (push) Waiting to run
Some checks are pending
Tests / Change detection (push) Waiting to run
Tests / Docs (push) Blocked by required conditions
Tests / Windows MSI (push) Blocked by required conditions
Tests / (push) Blocked by required conditions
Tests / Check if Autoconf files are up to date (push) Blocked by required conditions
Tests / Check if generated files are up to date (push) Blocked by required conditions
Tests / Sanitizers (push) Blocked by required conditions
Tests / Ubuntu SSL tests with OpenSSL (push) Blocked by required conditions
Tests / Ubuntu SSL tests with AWS-LC (push) Blocked by required conditions
Tests / Android (aarch64) (push) Blocked by required conditions
Tests / Android (x86_64) (push) Blocked by required conditions
Tests / WASI (push) Blocked by required conditions
Tests / Hypothesis tests on Ubuntu (push) Blocked by required conditions
Tests / Address sanitizer (push) Blocked by required conditions
Tests / Cross build Linux (push) Blocked by required conditions
Tests / CIFuzz (push) Blocked by required conditions
Tests / All required checks pass (push) Blocked by required conditions
Lint / lint (push) Waiting to run
mypy / Run mypy on Lib/tomllib (push) Waiting to run
mypy / Run mypy on Lib/_pyrepl (push) Waiting to run
mypy / Run mypy on Lib/test/libregrtest (push) Waiting to run
mypy / Run mypy on Tools/build (push) Waiting to run
mypy / Run mypy on Tools/cases_generator (push) Waiting to run
mypy / Run mypy on Tools/clinic (push) Waiting to run
mypy / Run mypy on Tools/jit (push) Waiting to run
mypy / Run mypy on Tools/peg_generator (push) Waiting to run
Optimize `asyncio.all_tasks()` for the common case where the event loop is running in the current thread by avoiding stop-the-world pauses and locking. This optimization is already present for `asyncio.current_task()` so we do the same for `asyncio.all_tasks()`.
This commit is contained in:
parent
ebf9938496
commit
95e5d59630
1 changed files with 38 additions and 24 deletions
|
|
@ -4079,30 +4079,44 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PyInterpreterState *interp = PyInterpreterState_Get();
|
||||
// Stop the world and traverse the per-thread linked list
|
||||
// of asyncio tasks for every thread, as well as the
|
||||
// interpreter's linked list, and add them to `tasks`.
|
||||
// The interpreter linked list is used for any lingering tasks
|
||||
// whose thread state has been deallocated while the task was
|
||||
// still alive. This can happen if a task is referenced by
|
||||
// a different thread, in which case the task is moved to
|
||||
// the interpreter's linked list from the thread's linked
|
||||
// list before deallocation. See PyThreadState_Clear.
|
||||
//
|
||||
// The stop-the-world pause is required so that no thread
|
||||
// modifies its linked list while being iterated here
|
||||
// in parallel. This design allows for lock-free
|
||||
// register_task/unregister_task for loops running in parallel
|
||||
// in different threads (the general case).
|
||||
_PyEval_StopTheWorld(interp);
|
||||
int ret = add_tasks_interp(interp, (PyListObject *)tasks);
|
||||
_PyEval_StartTheWorld(interp);
|
||||
if (ret < 0) {
|
||||
// call any escaping calls after starting the world to avoid any deadlocks.
|
||||
Py_DECREF(tasks);
|
||||
Py_DECREF(loop);
|
||||
return NULL;
|
||||
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
|
||||
if (ts->asyncio_running_loop == loop) {
|
||||
// Fast path for the current running loop of current thread
|
||||
// no locking or stop the world pause is required
|
||||
struct llist_node *head = &ts->asyncio_tasks_head;
|
||||
if (add_tasks_llist(head, (PyListObject *)tasks) < 0) {
|
||||
Py_DECREF(tasks);
|
||||
Py_DECREF(loop);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Slow path for loop running in different thread
|
||||
PyInterpreterState *interp = ts->base.interp;
|
||||
// Stop the world and traverse the per-thread linked list
|
||||
// of asyncio tasks for every thread, as well as the
|
||||
// interpreter's linked list, and add them to `tasks`.
|
||||
// The interpreter linked list is used for any lingering tasks
|
||||
// whose thread state has been deallocated while the task was
|
||||
// still alive. This can happen if a task is referenced by
|
||||
// a different thread, in which case the task is moved to
|
||||
// the interpreter's linked list from the thread's linked
|
||||
// list before deallocation. See PyThreadState_Clear.
|
||||
//
|
||||
// The stop-the-world pause is required so that no thread
|
||||
// modifies its linked list while being iterated here
|
||||
// in parallel. This design allows for lock-free
|
||||
// register_task/unregister_task for loops running in parallel
|
||||
// in different threads (the general case).
|
||||
_PyEval_StopTheWorld(interp);
|
||||
int ret = add_tasks_interp(interp, (PyListObject *)tasks);
|
||||
_PyEval_StartTheWorld(interp);
|
||||
if (ret < 0) {
|
||||
// call any escaping calls after starting the world to avoid any deadlocks.
|
||||
Py_DECREF(tasks);
|
||||
Py_DECREF(loop);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// All the tasks are now in the list, now filter the tasks which are done
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue