Skip to content

Commit 4994f24

Browse files
GH-100363: Speed up asyncio.get_running_loop (#100364)
1 parent 79311cb commit 4994f24

File tree

3 files changed

+14
-118
lines changed

3 files changed

+14
-118
lines changed

Lib/asyncio/events.py

+1
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ def on_fork():
836836
# Reset the loop and wakeupfd in the forked child process.
837837
if _event_loop_policy is not None:
838838
_event_loop_policy._local = BaseDefaultEventLoopPolicy._Local()
839+
_set_running_loop(None)
839840
signal.set_wakeup_fd(-1)
840841

841842
os.register_at_fork(after_in_child=on_fork)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Speed up :func:`asyncio.get_running_loop` by removing redundant ``getpid`` checks. Patch by Kumar Aditya.

Modules/_asynciomodule.c

+12-118
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ typedef struct {
2323
PyTypeObject *TaskStepMethWrapper_Type;
2424
PyTypeObject *FutureType;
2525
PyTypeObject *TaskType;
26-
PyTypeObject *PyRunningLoopHolder_Type;
2726

2827
PyObject *asyncio_mod;
2928
PyObject *context_kwname;
@@ -59,8 +58,8 @@ typedef struct {
5958
/* Imports from traceback. */
6059
PyObject *traceback_extract_stack;
6160

62-
PyObject *cached_running_holder; // Borrowed ref.
63-
volatile uint64_t cached_running_holder_tsid;
61+
PyObject *cached_running_loop; // Borrowed reference
62+
volatile uint64_t cached_running_loop_tsid;
6463

6564
/* Counter for autogenerated Task names */
6665
uint64_t task_name_counter;
@@ -138,14 +137,6 @@ typedef struct {
138137
PyObject *sw_arg;
139138
} TaskStepMethWrapper;
140139

141-
typedef struct {
142-
PyObject_HEAD
143-
PyObject *rl_loop;
144-
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
145-
pid_t rl_pid;
146-
#endif
147-
} PyRunningLoopHolder;
148-
149140

150141
#define Future_CheckExact(state, obj) Py_IS_TYPE(obj, state->FutureType)
151142
#define Task_CheckExact(state, obj) Py_IS_TYPE(obj, state->TaskType)
@@ -165,8 +156,6 @@ class _asyncio.Future "FutureObj *" "&Future_Type"
165156
/* Get FutureIter from Future */
166157
static PyObject * future_new_iter(PyObject *);
167158

168-
static PyRunningLoopHolder * new_running_loop_holder(asyncio_state *, PyObject *);
169-
170159

171160
static int
172161
_is_coroutine(asyncio_state *state, PyObject *coro)
@@ -264,11 +253,11 @@ get_running_loop(asyncio_state *state, PyObject **loop)
264253

265254
PyThreadState *ts = _PyThreadState_GET();
266255
uint64_t ts_id = PyThreadState_GetID(ts);
267-
if (state->cached_running_holder_tsid == ts_id &&
268-
state->cached_running_holder != NULL)
256+
if (state->cached_running_loop_tsid == ts_id &&
257+
state->cached_running_loop != NULL)
269258
{
270259
// Fast path, check the cache.
271-
rl = state->cached_running_holder; // borrowed
260+
rl = state->cached_running_loop;
272261
}
273262
else {
274263
PyObject *ts_dict = _PyThreadState_GetDict(ts); // borrowed
@@ -287,27 +276,16 @@ get_running_loop(asyncio_state *state, PyObject **loop)
287276
}
288277
}
289278

290-
state->cached_running_holder = rl; // borrowed
291-
state->cached_running_holder_tsid = ts_id;
279+
state->cached_running_loop = rl;
280+
state->cached_running_loop_tsid = ts_id;
292281
}
293282

294-
assert(Py_IS_TYPE(rl, state->PyRunningLoopHolder_Type));
295-
PyObject *running_loop = ((PyRunningLoopHolder *)rl)->rl_loop;
296-
297-
if (running_loop == Py_None) {
298-
goto not_found;
299-
}
300283

301-
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
302-
/* On Windows there is no getpid, but there is also no os.fork(),
303-
so there is no need for this check.
304-
*/
305-
if (getpid() != ((PyRunningLoopHolder *)rl)->rl_pid) {
284+
if (rl == Py_None) {
306285
goto not_found;
307286
}
308-
#endif
309287

310-
*loop = Py_NewRef(running_loop);
288+
*loop = Py_NewRef(rl);
311289
return 0;
312290

313291
not_found:
@@ -335,22 +313,14 @@ set_running_loop(asyncio_state *state, PyObject *loop)
335313
PyExc_RuntimeError, "thread-local storage is not available");
336314
return -1;
337315
}
338-
339-
PyRunningLoopHolder *rl = new_running_loop_holder(state, loop);
340-
if (rl == NULL) {
341-
return -1;
342-
}
343-
344316
if (PyDict_SetItem(
345-
ts_dict, &_Py_ID(__asyncio_running_event_loop__), (PyObject *)rl) < 0)
317+
ts_dict, &_Py_ID(__asyncio_running_event_loop__), loop) < 0)
346318
{
347-
Py_DECREF(rl); // will cleanup loop & current_pid
348319
return -1;
349320
}
350-
Py_DECREF(rl);
351321

352-
state->cached_running_holder = (PyObject *)rl;
353-
state->cached_running_holder_tsid = PyThreadState_GetID(tstate);
322+
state->cached_running_loop = loop; // borrowed, kept alive by ts_dict
323+
state->cached_running_loop_tsid = PyThreadState_GetID(tstate);
354324

355325
return 0;
356326
}
@@ -3344,79 +3314,6 @@ _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task)
33443314
}
33453315

33463316

3347-
/*********************** PyRunningLoopHolder ********************/
3348-
3349-
3350-
static PyRunningLoopHolder *
3351-
new_running_loop_holder(asyncio_state *state, PyObject *loop)
3352-
{
3353-
PyRunningLoopHolder *rl = PyObject_GC_New(
3354-
PyRunningLoopHolder, state->PyRunningLoopHolder_Type);
3355-
if (rl == NULL) {
3356-
return NULL;
3357-
}
3358-
3359-
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
3360-
rl->rl_pid = getpid();
3361-
#endif
3362-
rl->rl_loop = Py_NewRef(loop);
3363-
3364-
PyObject_GC_Track(rl);
3365-
return rl;
3366-
}
3367-
3368-
3369-
static int
3370-
PyRunningLoopHolder_clear(PyRunningLoopHolder *rl)
3371-
{
3372-
Py_CLEAR(rl->rl_loop);
3373-
return 0;
3374-
}
3375-
3376-
3377-
static int
3378-
PyRunningLoopHolder_traverse(PyRunningLoopHolder *rl, visitproc visit,
3379-
void *arg)
3380-
{
3381-
Py_VISIT(Py_TYPE(rl));
3382-
Py_VISIT(rl->rl_loop);
3383-
return 0;
3384-
}
3385-
3386-
3387-
static void
3388-
PyRunningLoopHolder_tp_dealloc(PyRunningLoopHolder *rl)
3389-
{
3390-
asyncio_state *state = get_asyncio_state_by_def((PyObject *)rl);
3391-
if (state->cached_running_holder == (PyObject *)rl) {
3392-
state->cached_running_holder = NULL;
3393-
}
3394-
PyTypeObject *tp = Py_TYPE(rl);
3395-
PyObject_GC_UnTrack(rl);
3396-
PyRunningLoopHolder_clear(rl);
3397-
PyObject_GC_Del(rl);
3398-
Py_DECREF(tp);
3399-
}
3400-
3401-
3402-
static PyType_Slot PyRunningLoopHolder_slots[] = {
3403-
{Py_tp_getattro, PyObject_GenericGetAttr},
3404-
{Py_tp_dealloc, (destructor)PyRunningLoopHolder_tp_dealloc},
3405-
{Py_tp_traverse, (traverseproc)PyRunningLoopHolder_traverse},
3406-
{Py_tp_clear, PyRunningLoopHolder_clear},
3407-
{0, NULL},
3408-
};
3409-
3410-
3411-
static PyType_Spec PyRunningLoopHolder_spec = {
3412-
.name = "_asyncio._RunningLoopHolder",
3413-
.basicsize = sizeof(PyRunningLoopHolder),
3414-
.slots = PyRunningLoopHolder_slots,
3415-
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
3416-
Py_TPFLAGS_IMMUTABLETYPE),
3417-
};
3418-
3419-
34203317
/*********************** Module **************************/
34213318

34223319

@@ -3448,7 +3345,6 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
34483345
Py_VISIT(state->TaskStepMethWrapper_Type);
34493346
Py_VISIT(state->FutureType);
34503347
Py_VISIT(state->TaskType);
3451-
Py_VISIT(state->PyRunningLoopHolder_Type);
34523348

34533349
Py_VISIT(state->asyncio_mod);
34543350
Py_VISIT(state->traceback_extract_stack);
@@ -3486,7 +3382,6 @@ module_clear(PyObject *mod)
34863382
Py_CLEAR(state->TaskStepMethWrapper_Type);
34873383
Py_CLEAR(state->FutureType);
34883384
Py_CLEAR(state->TaskType);
3489-
Py_CLEAR(state->PyRunningLoopHolder_Type);
34903385

34913386
Py_CLEAR(state->asyncio_mod);
34923387
Py_CLEAR(state->traceback_extract_stack);
@@ -3625,7 +3520,6 @@ module_exec(PyObject *mod)
36253520
} while (0)
36263521

36273522
CREATE_TYPE(mod, state->TaskStepMethWrapper_Type, &TaskStepMethWrapper_spec, NULL);
3628-
CREATE_TYPE(mod, state->PyRunningLoopHolder_Type, &PyRunningLoopHolder_spec, NULL);
36293523
CREATE_TYPE(mod, state->FutureIterType, &FutureIter_spec, NULL);
36303524
CREATE_TYPE(mod, state->FutureType, &Future_spec, NULL);
36313525
CREATE_TYPE(mod, state->TaskType, &Task_spec, state->FutureType);

0 commit comments

Comments
 (0)