bpo-32296: Make get_running_loop() another 4-5x faster (#5277)
This commit is contained in:
parent
e768c86ef4
commit
9d411c119f
|
@ -26,7 +26,6 @@ _Py_IDENTIFIER(_wakeup);
|
||||||
/* State of the _asyncio module */
|
/* State of the _asyncio module */
|
||||||
static PyObject *asyncio_mod;
|
static PyObject *asyncio_mod;
|
||||||
static PyObject *inspect_isgenerator;
|
static PyObject *inspect_isgenerator;
|
||||||
static PyObject *os_getpid;
|
|
||||||
static PyObject *traceback_extract_stack;
|
static PyObject *traceback_extract_stack;
|
||||||
static PyObject *asyncio_get_event_loop_policy;
|
static PyObject *asyncio_get_event_loop_policy;
|
||||||
static PyObject *asyncio_future_repr_info_func;
|
static PyObject *asyncio_future_repr_info_func;
|
||||||
|
@ -38,6 +37,9 @@ static PyObject *asyncio_InvalidStateError;
|
||||||
static PyObject *asyncio_CancelledError;
|
static PyObject *asyncio_CancelledError;
|
||||||
static PyObject *context_kwname;
|
static PyObject *context_kwname;
|
||||||
|
|
||||||
|
static PyObject *cached_running_holder;
|
||||||
|
static volatile uint64_t cached_running_holder_tsid;
|
||||||
|
|
||||||
|
|
||||||
/* WeakSet containing all alive tasks. */
|
/* WeakSet containing all alive tasks. */
|
||||||
static PyObject *all_tasks;
|
static PyObject *all_tasks;
|
||||||
|
@ -95,9 +97,18 @@ typedef struct {
|
||||||
TaskObj *ww_task;
|
TaskObj *ww_task;
|
||||||
} TaskWakeupMethWrapper;
|
} TaskWakeupMethWrapper;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PyObject_HEAD
|
||||||
|
PyObject *rl_loop;
|
||||||
|
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
|
||||||
|
pid_t rl_pid;
|
||||||
|
#endif
|
||||||
|
} PyRunningLoopHolder;
|
||||||
|
|
||||||
|
|
||||||
static PyTypeObject FutureType;
|
static PyTypeObject FutureType;
|
||||||
static PyTypeObject TaskType;
|
static PyTypeObject TaskType;
|
||||||
|
static PyTypeObject PyRunningLoopHolder_Type;
|
||||||
|
|
||||||
|
|
||||||
#define Future_CheckExact(obj) (Py_TYPE(obj) == &FutureType)
|
#define Future_CheckExact(obj) (Py_TYPE(obj) == &FutureType)
|
||||||
|
@ -116,9 +127,11 @@ class _asyncio.Future "FutureObj *" "&Future_Type"
|
||||||
|
|
||||||
|
|
||||||
/* Get FutureIter from Future */
|
/* Get FutureIter from Future */
|
||||||
static PyObject* future_new_iter(PyObject *);
|
static PyObject * future_new_iter(PyObject *);
|
||||||
static inline int future_call_schedule_callbacks(FutureObj *);
|
static inline int future_call_schedule_callbacks(FutureObj *);
|
||||||
|
|
||||||
|
static PyRunningLoopHolder * new_running_loop_holder(PyObject *);
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_is_coroutine(PyObject *coro)
|
_is_coroutine(PyObject *coro)
|
||||||
|
@ -214,60 +227,57 @@ get_future_loop(PyObject *fut)
|
||||||
static int
|
static int
|
||||||
get_running_loop(PyObject **loop)
|
get_running_loop(PyObject **loop)
|
||||||
{
|
{
|
||||||
PyObject *ts_dict;
|
PyObject *rl;
|
||||||
PyObject *running_tuple;
|
|
||||||
PyObject *running_loop;
|
|
||||||
PyObject *running_loop_pid;
|
|
||||||
PyObject *current_pid;
|
|
||||||
int same_pid;
|
|
||||||
|
|
||||||
ts_dict = PyThreadState_GetDict(); // borrowed
|
PyThreadState *ts = PyThreadState_Get();
|
||||||
if (ts_dict == NULL) {
|
if (ts->id == cached_running_holder_tsid && cached_running_holder != NULL) {
|
||||||
PyErr_SetString(
|
// Fast path, check the cache.
|
||||||
PyExc_RuntimeError, "thread-local storage is not available");
|
rl = cached_running_holder; // borrowed
|
||||||
goto error;
|
}
|
||||||
|
else {
|
||||||
|
if (ts->dict == NULL) {
|
||||||
|
goto not_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
rl = _PyDict_GetItemIdWithError(
|
||||||
|
ts->dict, &PyId___asyncio_running_event_loop__); // borrowed
|
||||||
|
if (rl == NULL) {
|
||||||
|
if (PyErr_Occurred()) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
goto not_found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cached_running_holder = rl; // borrowed
|
||||||
|
cached_running_holder_tsid = ts->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
running_tuple = _PyDict_GetItemId(
|
assert(Py_TYPE(rl) == &PyRunningLoopHolder_Type);
|
||||||
ts_dict, &PyId___asyncio_running_event_loop__); // borrowed
|
PyObject *running_loop = ((PyRunningLoopHolder *)rl)->rl_loop;
|
||||||
if (running_tuple == NULL) {
|
|
||||||
/* _PyDict_GetItemId doesn't set an error if key is not found */
|
|
||||||
goto not_found;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(PyTuple_CheckExact(running_tuple));
|
|
||||||
assert(PyTuple_Size(running_tuple) == 2);
|
|
||||||
running_loop = PyTuple_GET_ITEM(running_tuple, 0); // borrowed
|
|
||||||
running_loop_pid = PyTuple_GET_ITEM(running_tuple, 1); // borrowed
|
|
||||||
|
|
||||||
if (running_loop == Py_None) {
|
if (running_loop == Py_None) {
|
||||||
goto not_found;
|
goto not_found;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_pid = _PyObject_CallNoArg(os_getpid);
|
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
|
||||||
if (current_pid == NULL) {
|
/* On Windows there is no getpid, but there is also no os.fork(),
|
||||||
goto error;
|
so there is no need for this check.
|
||||||
}
|
*/
|
||||||
same_pid = PyObject_RichCompareBool(current_pid, running_loop_pid, Py_EQ);
|
if (getpid() != ((PyRunningLoopHolder *)rl)->rl_pid) {
|
||||||
Py_DECREF(current_pid);
|
goto not_found;
|
||||||
if (same_pid == -1) {
|
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (same_pid) {
|
Py_INCREF(running_loop);
|
||||||
// current_pid == running_loop_pid
|
*loop = running_loop;
|
||||||
goto found;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
not_found:
|
not_found:
|
||||||
*loop = NULL;
|
*loop = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
found:
|
|
||||||
Py_INCREF(running_loop);
|
|
||||||
*loop = running_loop;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
error:
|
error:
|
||||||
*loop = NULL;
|
*loop = NULL;
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -277,38 +287,28 @@ error:
|
||||||
static int
|
static int
|
||||||
set_running_loop(PyObject *loop)
|
set_running_loop(PyObject *loop)
|
||||||
{
|
{
|
||||||
PyObject *ts_dict;
|
cached_running_holder = NULL;
|
||||||
PyObject *running_tuple;
|
cached_running_holder_tsid = 0;
|
||||||
PyObject *current_pid;
|
|
||||||
|
|
||||||
ts_dict = PyThreadState_GetDict(); // borrowed
|
PyObject *ts_dict = PyThreadState_GetDict(); // borrowed
|
||||||
if (ts_dict == NULL) {
|
if (ts_dict == NULL) {
|
||||||
PyErr_SetString(
|
PyErr_SetString(
|
||||||
PyExc_RuntimeError, "thread-local storage is not available");
|
PyExc_RuntimeError, "thread-local storage is not available");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
current_pid = _PyObject_CallNoArg(os_getpid);
|
PyRunningLoopHolder *rl = new_running_loop_holder(loop);
|
||||||
if (current_pid == NULL) {
|
if (rl == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
running_tuple = PyTuple_New(2);
|
|
||||||
if (running_tuple == NULL) {
|
|
||||||
Py_DECREF(current_pid);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_INCREF(loop);
|
|
||||||
PyTuple_SET_ITEM(running_tuple, 0, loop);
|
|
||||||
PyTuple_SET_ITEM(running_tuple, 1, current_pid); // borrowed
|
|
||||||
|
|
||||||
if (_PyDict_SetItemId(
|
if (_PyDict_SetItemId(
|
||||||
ts_dict, &PyId___asyncio_running_event_loop__, running_tuple)) {
|
ts_dict, &PyId___asyncio_running_event_loop__, (PyObject *)rl) < 0)
|
||||||
Py_DECREF(running_tuple); // will cleanup loop & current_pid
|
{
|
||||||
|
Py_DECREF(rl); // will cleanup loop & current_pid
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
Py_DECREF(running_tuple);
|
Py_DECREF(rl);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3184,6 +3184,47 @@ _asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*********************** PyRunningLoopHolder ********************/
|
||||||
|
|
||||||
|
|
||||||
|
static PyRunningLoopHolder *
|
||||||
|
new_running_loop_holder(PyObject *loop)
|
||||||
|
{
|
||||||
|
PyRunningLoopHolder *rl = PyObject_New(
|
||||||
|
PyRunningLoopHolder, &PyRunningLoopHolder_Type);
|
||||||
|
if (rl == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_GETPID) && !defined(MS_WINDOWS)
|
||||||
|
rl->rl_pid = getpid();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Py_INCREF(loop);
|
||||||
|
rl->rl_loop = loop;
|
||||||
|
|
||||||
|
return rl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
PyRunningLoopHolder_tp_dealloc(PyRunningLoopHolder *rl)
|
||||||
|
{
|
||||||
|
Py_CLEAR(rl->rl_loop);
|
||||||
|
PyObject_Free(rl);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyTypeObject PyRunningLoopHolder_Type = {
|
||||||
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
|
"_RunningLoopHolder",
|
||||||
|
sizeof(PyRunningLoopHolder),
|
||||||
|
.tp_getattro = PyObject_GenericGetAttr,
|
||||||
|
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||||
|
.tp_dealloc = (destructor)PyRunningLoopHolder_tp_dealloc,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*********************** Module **************************/
|
/*********************** Module **************************/
|
||||||
|
|
||||||
|
|
||||||
|
@ -3212,7 +3253,6 @@ module_free(void *m)
|
||||||
{
|
{
|
||||||
Py_CLEAR(asyncio_mod);
|
Py_CLEAR(asyncio_mod);
|
||||||
Py_CLEAR(inspect_isgenerator);
|
Py_CLEAR(inspect_isgenerator);
|
||||||
Py_CLEAR(os_getpid);
|
|
||||||
Py_CLEAR(traceback_extract_stack);
|
Py_CLEAR(traceback_extract_stack);
|
||||||
Py_CLEAR(asyncio_future_repr_info_func);
|
Py_CLEAR(asyncio_future_repr_info_func);
|
||||||
Py_CLEAR(asyncio_get_event_loop_policy);
|
Py_CLEAR(asyncio_get_event_loop_policy);
|
||||||
|
@ -3295,9 +3335,6 @@ module_init(void)
|
||||||
WITH_MOD("inspect")
|
WITH_MOD("inspect")
|
||||||
GET_MOD_ATTR(inspect_isgenerator, "isgenerator")
|
GET_MOD_ATTR(inspect_isgenerator, "isgenerator")
|
||||||
|
|
||||||
WITH_MOD("os")
|
|
||||||
GET_MOD_ATTR(os_getpid, "getpid")
|
|
||||||
|
|
||||||
WITH_MOD("traceback")
|
WITH_MOD("traceback")
|
||||||
GET_MOD_ATTR(traceback_extract_stack, "extract_stack")
|
GET_MOD_ATTR(traceback_extract_stack, "extract_stack")
|
||||||
|
|
||||||
|
@ -3370,6 +3407,9 @@ PyInit__asyncio(void)
|
||||||
if (PyType_Ready(&TaskType) < 0) {
|
if (PyType_Ready(&TaskType) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (PyType_Ready(&PyRunningLoopHolder_Type) < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
PyObject *m = PyModule_Create(&_asynciomodule);
|
PyObject *m = PyModule_Create(&_asynciomodule);
|
||||||
if (m == NULL) {
|
if (m == NULL) {
|
||||||
|
|
Loading…
Reference in New Issue