I've been exploring the async source code and noticed that the function _get_running_loop() is defined both in Python and has a note stating it's implemented in C (in _asynciomodule.c).
# python3.11/asyncio/events.py
def get_running_loop():
"""Return the running event loop. Raise a RuntimeError if there is none.
This function is thread-specific.
"""
# NOTE: this function is implemented in C (see _asynciomodule.c)
loop = _get_running_loop()
if loop is None:
raise RuntimeError('no running event loop')
return loop
def _get_running_loop():
"""Return the running event loop or None.
This is a low-level function intended to be used by event loops.
This function is thread-specific.
"""
# NOTE: this function is implemented in C (see _asynciomodule.c)
running_loop, pid = _running_loop.loop_pid
if running_loop is not None and pid == os.getpid():
return running_loop
If _get_running_loop() is already defined in Python, why is it said the actual implementation is written in C?
The following code in Cpython looks like the real implementation:
static PyObject *
_asyncio_get_running_loop_impl(PyObject *module)
/*[clinic end generated code: output=c247b5f9e529530e input=2a3bf02ba39f173d]*/
{
PyObject *loop;
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
loop = Py_XNewRef(ts->asyncio_running_loop);
if (loop == NULL) {
/* There's no currently running event loop */
PyErr_SetString(
PyExc_RuntimeError, "no running event loop");
return NULL;
}
return loop;
}
I'm aware that asyncio uses C extensions for performance reasons, but I’d like to understand how this mechanism works, specifically how Python binds the Python-level function to the C-level implementation.
Thank you!
asyncio/events.pyfile where that Python specific version is shadowed by the C implementation should_asyncio, the C module, is successfully imported.