mirror of https://github.com/python/cpython
GH-100363: Speed up `asyncio.get_running_loop` (#100364)
This commit is contained in:
parent
79311cbfe7
commit
4994f2488f
|
@ -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)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Speed up :func:`asyncio.get_running_loop` by removing redundant ``getpid`` checks. Patch by Kumar Aditya.
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue