Skip to content

Commit 7e3b788

Browse files
gh-128002: use efficient linked list implementation for eager tasks in asyncio (#130518)
1 parent f97e409 commit 7e3b788

File tree

2 files changed

+33
-42
lines changed

2 files changed

+33
-42
lines changed

Lib/asyncio/tasks.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1110,7 +1110,6 @@ def _unregister_eager_task(task):
11101110
from _asyncio import (_register_task, _register_eager_task,
11111111
_unregister_task, _unregister_eager_task,
11121112
_enter_task, _leave_task, _swap_current_task,
1113-
_scheduled_tasks, _eager_tasks,
11141113
current_task, all_tasks)
11151114
except ImportError:
11161115
pass

Modules/_asynciomodule.c

Lines changed: 33 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,9 @@ typedef struct {
143143
inherit from native asyncio.Task */
144144
PyObject *non_asyncio_tasks;
145145

146-
/* Set containing all eagerly executing tasks. */
147-
PyObject *eager_tasks;
146+
/* Set containing all 3rd party eagerly executing tasks which don't
147+
inherit from native asyncio.Task */
148+
PyObject *non_asyncio_eager_tasks;
148149

149150
/* An isinstance type cache for the 'is_coroutine()' function. */
150151
PyObject *iscoroutine_typecache;
@@ -2180,12 +2181,6 @@ register_task(TaskObj *task)
21802181
llist_insert_tail(head, &task->task_node);
21812182
}
21822183

2183-
static int
2184-
register_eager_task(asyncio_state *state, PyObject *task)
2185-
{
2186-
return PySet_Add(state->eager_tasks, task);
2187-
}
2188-
21892184
static inline void
21902185
unregister_task_safe(TaskObj *task)
21912186
{
@@ -2219,12 +2214,6 @@ unregister_task(TaskObj *task)
22192214
#endif
22202215
}
22212216

2222-
static int
2223-
unregister_eager_task(asyncio_state *state, PyObject *task)
2224-
{
2225-
return PySet_Discard(state->eager_tasks, task);
2226-
}
2227-
22282217
static int
22292218
enter_task(PyObject *loop, PyObject *task)
22302219
{
@@ -3472,11 +3461,11 @@ task_eager_start(asyncio_state *state, TaskObj *task)
34723461
if (prevtask == NULL) {
34733462
return -1;
34743463
}
3475-
3476-
if (register_eager_task(state, (PyObject *)task) == -1) {
3477-
Py_DECREF(prevtask);
3478-
return -1;
3479-
}
3464+
// register the task into the linked list of tasks
3465+
// if the task completes eagerly (without suspending) then it will unregister itself
3466+
// in future_schedule_callbacks when done, otherwise
3467+
// it will continue as a regular (non-eager) asyncio task
3468+
register_task(task);
34803469

34813470
if (PyContext_Enter(task->task_context) == -1) {
34823471
Py_DECREF(prevtask);
@@ -3506,17 +3495,11 @@ task_eager_start(asyncio_state *state, TaskObj *task)
35063495
Py_DECREF(curtask);
35073496
}
35083497

3509-
if (unregister_eager_task(state, (PyObject *)task) == -1) {
3510-
retval = -1;
3511-
}
3512-
35133498
if (PyContext_Exit(task->task_context) == -1) {
35143499
retval = -1;
35153500
}
35163501

3517-
if (task->task_state == STATE_PENDING) {
3518-
register_task(task);
3519-
} else {
3502+
if (task->task_state != STATE_PENDING) {
35203503
// This seems to really help performance on pyperformance benchmarks
35213504
clear_task_coro(task);
35223505
}
@@ -3735,9 +3718,18 @@ _asyncio__register_eager_task_impl(PyObject *module, PyObject *task)
37353718
/*[clinic end generated code: output=dfe1d45367c73f1a input=237f684683398c51]*/
37363719
{
37373720
asyncio_state *state = get_asyncio_state(module);
3738-
if (register_eager_task(state, task) < 0) {
3721+
3722+
if (Task_Check(state, task)) {
3723+
// task is an asyncio.Task instance or subclass, use efficient
3724+
// linked-list implementation.
3725+
register_task((TaskObj *)task);
3726+
Py_RETURN_NONE;
3727+
}
3728+
3729+
if (PySet_Add(state->non_asyncio_eager_tasks, task) < 0) {
37393730
return NULL;
37403731
}
3732+
37413733
Py_RETURN_NONE;
37423734
}
37433735

@@ -3785,9 +3777,17 @@ _asyncio__unregister_eager_task_impl(PyObject *module, PyObject *task)
37853777
/*[clinic end generated code: output=a426922bd07f23d1 input=9d07401ef14ee048]*/
37863778
{
37873779
asyncio_state *state = get_asyncio_state(module);
3788-
if (unregister_eager_task(state, task) < 0) {
3780+
if (Task_Check(state, task)) {
3781+
// task is an asyncio.Task instance or subclass, use efficient
3782+
// linked-list implementation.
3783+
unregister_task((TaskObj *)task);
3784+
Py_RETURN_NONE;
3785+
}
3786+
3787+
if (PySet_Discard(state->non_asyncio_eager_tasks, task) < 0) {
37893788
return NULL;
37903789
}
3790+
37913791
Py_RETURN_NONE;
37923792
}
37933793

@@ -4041,7 +4041,7 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
40414041
Py_DECREF(loop);
40424042
return NULL;
40434043
}
4044-
if (PyList_Extend(tasks, state->eager_tasks) < 0) {
4044+
if (PyList_Extend(tasks, state->non_asyncio_eager_tasks) < 0) {
40454045
Py_DECREF(tasks);
40464046
Py_DECREF(loop);
40474047
return NULL;
@@ -4179,7 +4179,7 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
41794179
Py_VISIT(state->asyncio_CancelledError);
41804180

41814181
Py_VISIT(state->non_asyncio_tasks);
4182-
Py_VISIT(state->eager_tasks);
4182+
Py_VISIT(state->non_asyncio_eager_tasks);
41834183
Py_VISIT(state->iscoroutine_typecache);
41844184

41854185
Py_VISIT(state->context_kwname);
@@ -4209,7 +4209,7 @@ module_clear(PyObject *mod)
42094209
Py_CLEAR(state->asyncio_CancelledError);
42104210

42114211
Py_CLEAR(state->non_asyncio_tasks);
4212-
Py_CLEAR(state->eager_tasks);
4212+
Py_CLEAR(state->non_asyncio_eager_tasks);
42134213
Py_CLEAR(state->iscoroutine_typecache);
42144214

42154215
Py_CLEAR(state->context_kwname);
@@ -4292,8 +4292,8 @@ module_init(asyncio_state *state)
42924292
goto fail;
42934293
}
42944294

4295-
state->eager_tasks = PySet_New(NULL);
4296-
if (state->eager_tasks == NULL) {
4295+
state->non_asyncio_eager_tasks = PySet_New(NULL);
4296+
if (state->non_asyncio_eager_tasks == NULL) {
42974297
goto fail;
42984298
}
42994299

@@ -4363,14 +4363,6 @@ module_exec(PyObject *mod)
43634363
return -1;
43644364
}
43654365

4366-
if (PyModule_AddObjectRef(mod, "_scheduled_tasks", state->non_asyncio_tasks) < 0) {
4367-
return -1;
4368-
}
4369-
4370-
if (PyModule_AddObjectRef(mod, "_eager_tasks", state->eager_tasks) < 0) {
4371-
return -1;
4372-
}
4373-
43744366
return 0;
43754367
}
43764368

0 commit comments

Comments
 (0)