GH-100363: Speed up `asyncio.get_running_loop` (#100364)

This commit is contained in:
Kumar Aditya 2022-12-21 15:19:44 +05:30 committed by GitHub
parent 79311cbfe7
commit 4994f2488f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 14 additions and 118 deletions

View File

@ -836,6 +836,7 @@ if hasattr(os, 'fork'):
# Reset the loop and wakeupfd in the forked child process.
if _event_loop_policy is not None:
_event_loop_policy._local = BaseDefaultEventLoopPolicy._Local()
_set_running_loop(None)
signal.set_wakeup_fd(-1)
os.register_at_fork(after_in_child=on_fork)

View File

@ -0,0 +1 @@
Speed up :func:`asyncio.get_running_loop` by removing redundant ``getpid`` checks. Patch by Kumar Aditya.

View File

@ -23,7 +23,6 @@ typedef struct {
PyTypeObject *TaskStepMethWrapper_Type;
PyTypeObject *FutureType;
PyTypeObject *TaskType;
PyTypeObject *PyRunningLoopHolder_Type;
PyObject *asyncio_mod;
PyObject *context_kwname;
@ -59,8 +58,8 @@ typedef struct {
/* Imports from traceback. */
PyObject *traceback_extract_stack;
PyObject *cached_running_holder; // Borrowed ref.
volatile uint64_t cached_running_holder_tsid;
PyObject *cached_running_loop; // Borrowed reference
volatile uint64_t cached_running_loop_tsid;
/* Counter for autogenerated Task names */
uint64_t task_name_counter;
@ -138,14 +137,6 @@ typedef struct {
PyObject *sw_arg;
} TaskStepMethWrapper;
typedef struct {
PyObject_HEAD
PyObject *rl_loop;
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
pid_t rl_pid;
#endif
} PyRunningLoopHolder;
#define Future_CheckExact(state, obj) Py_IS_TYPE(obj, state->FutureType)
#define Task_CheckExact(state, obj) Py_IS_TYPE(obj, state->TaskType)
@ -165,8 +156,6 @@ class _asyncio.Future "FutureObj *" "&Future_Type"
/* Get FutureIter from Future */
static PyObject * future_new_iter(PyObject *);
static PyRunningLoopHolder * new_running_loop_holder(asyncio_state *, PyObject *);
static int
_is_coroutine(asyncio_state *state, PyObject *coro)
@ -264,11 +253,11 @@ get_running_loop(asyncio_state *state, PyObject **loop)
PyThreadState *ts = _PyThreadState_GET();
uint64_t ts_id = PyThreadState_GetID(ts);
if (state->cached_running_holder_tsid == ts_id &&
state->cached_running_holder != NULL)
if (state->cached_running_loop_tsid == ts_id &&
state->cached_running_loop != NULL)
{
// Fast path, check the cache.
rl = state->cached_running_holder; // borrowed
rl = state->cached_running_loop;
}
else {
PyObject *ts_dict = _PyThreadState_GetDict(ts); // borrowed
@ -287,27 +276,16 @@ get_running_loop(asyncio_state *state, PyObject **loop)
}
}
state->cached_running_holder = rl; // borrowed
state->cached_running_holder_tsid = ts_id;
state->cached_running_loop = rl;
state->cached_running_loop_tsid = ts_id;
}
assert(Py_IS_TYPE(rl, state->PyRunningLoopHolder_Type));
PyObject *running_loop = ((PyRunningLoopHolder *)rl)->rl_loop;
if (running_loop == Py_None) {
if (rl == Py_None) {
goto not_found;
}
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
/* On Windows there is no getpid, but there is also no os.fork(),
so there is no need for this check.
*/
if (getpid() != ((PyRunningLoopHolder *)rl)->rl_pid) {
goto not_found;
}
#endif
*loop = Py_NewRef(running_loop);
*loop = Py_NewRef(rl);
return 0;
not_found:
@ -335,22 +313,14 @@ set_running_loop(asyncio_state *state, PyObject *loop)
PyExc_RuntimeError, "thread-local storage is not available");
return -1;
}
PyRunningLoopHolder *rl = new_running_loop_holder(state, loop);
if (rl == NULL) {
return -1;
}
if (PyDict_SetItem(
ts_dict, &_Py_ID(__asyncio_running_event_loop__), (PyObject *)rl) < 0)
ts_dict, &_Py_ID(__asyncio_running_event_loop__), loop) < 0)
{
Py_DECREF(rl); // will cleanup loop & current_pid
return -1;
}
Py_DECREF(rl);
state->cached_running_holder = (PyObject *)rl;
state->cached_running_holder_tsid = PyThreadState_GetID(tstate);
state->cached_running_loop = loop; // borrowed, kept alive by ts_dict
state->cached_running_loop_tsid = PyThreadState_GetID(tstate);
return 0;
}
@ -3344,79 +3314,6 @@ _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task)
}
/*********************** PyRunningLoopHolder ********************/
static PyRunningLoopHolder *
new_running_loop_holder(asyncio_state *state, PyObject *loop)
{
PyRunningLoopHolder *rl = PyObject_GC_New(
PyRunningLoopHolder, state->PyRunningLoopHolder_Type);
if (rl == NULL) {
return NULL;
}
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
rl->rl_pid = getpid();
#endif
rl->rl_loop = Py_NewRef(loop);
PyObject_GC_Track(rl);
return rl;
}
static int
PyRunningLoopHolder_clear(PyRunningLoopHolder *rl)
{
Py_CLEAR(rl->rl_loop);
return 0;
}
static int
PyRunningLoopHolder_traverse(PyRunningLoopHolder *rl, visitproc visit,
void *arg)
{
Py_VISIT(Py_TYPE(rl));
Py_VISIT(rl->rl_loop);
return 0;
}
static void
PyRunningLoopHolder_tp_dealloc(PyRunningLoopHolder *rl)
{
asyncio_state *state = get_asyncio_state_by_def((PyObject *)rl);
if (state->cached_running_holder == (PyObject *)rl) {
state->cached_running_holder = NULL;
}
PyTypeObject *tp = Py_TYPE(rl);
PyObject_GC_UnTrack(rl);
PyRunningLoopHolder_clear(rl);
PyObject_GC_Del(rl);
Py_DECREF(tp);
}
static PyType_Slot PyRunningLoopHolder_slots[] = {
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_dealloc, (destructor)PyRunningLoopHolder_tp_dealloc},
{Py_tp_traverse, (traverseproc)PyRunningLoopHolder_traverse},
{Py_tp_clear, PyRunningLoopHolder_clear},
{0, NULL},
};
static PyType_Spec PyRunningLoopHolder_spec = {
.name = "_asyncio._RunningLoopHolder",
.basicsize = sizeof(PyRunningLoopHolder),
.slots = PyRunningLoopHolder_slots,
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_IMMUTABLETYPE),
};
/*********************** Module **************************/
@ -3448,7 +3345,6 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
Py_VISIT(state->TaskStepMethWrapper_Type);
Py_VISIT(state->FutureType);
Py_VISIT(state->TaskType);
Py_VISIT(state->PyRunningLoopHolder_Type);
Py_VISIT(state->asyncio_mod);
Py_VISIT(state->traceback_extract_stack);
@ -3486,7 +3382,6 @@ module_clear(PyObject *mod)
Py_CLEAR(state->TaskStepMethWrapper_Type);
Py_CLEAR(state->FutureType);
Py_CLEAR(state->TaskType);
Py_CLEAR(state->PyRunningLoopHolder_Type);
Py_CLEAR(state->asyncio_mod);
Py_CLEAR(state->traceback_extract_stack);
@ -3625,7 +3520,6 @@ module_exec(PyObject *mod)
} while (0)
CREATE_TYPE(mod, state->TaskStepMethWrapper_Type, &TaskStepMethWrapper_spec, NULL);
CREATE_TYPE(mod, state->PyRunningLoopHolder_Type, &PyRunningLoopHolder_spec, NULL);
CREATE_TYPE(mod, state->FutureIterType, &FutureIter_spec, NULL);
CREATE_TYPE(mod, state->FutureType, &Future_spec, NULL);
CREATE_TYPE(mod, state->TaskType, &Task_spec, state->FutureType);