我一直在探索
async
源代码,并注意到函数 _get_running_loop()
都是在 Python 中定义的,并且有一个注释说明它是在 C 中实现的(在 _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
如果
_get_running_loop()
已经在Python中定义了,为什么说实际实现是用C编写的?
Cpython中的以下代码看起来像真正的实现:
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;
}
我知道
asyncio
出于性能原因使用C扩展,但我想了解这种机制是如何工作的,特别是Python如何将Python级函数绑定到C级实现。
谢谢!
一般来说,就Python的stdlib而言,其中给定模块可以使用C实现,它们必须遵循
PEP 399
中概述的要求,即即使有C版本,也必须提供纯Python实现继续前进。
因此,对于受影响的 stdlib 模块,它们将被结构化以便纯 Python 类/函数可用,并且通常在这些模块的最后会有一个
try: ... except ImportError:
块,它将尝试导入 C版本,当导入成功时,基于 C 的版本将遮蔽 Python 定义的版本,失败时,要么不发生遮蔽,要么定义一个纯 Python 版本以实现兼容性。
例如,
asyncio.events
模块具有类似以下内容的内容,它将在文件开头隐藏纯Python实现(示例已被截断):
# Alias pure-Python implementations for testing purposes.
_py__get_running_loop = _get_running_loop
...
try:
# get_event_loop() is one of the most frequently called
# functions in asyncio. Pure Python implementation is
# about 4 times slower than C-accelerated.
from _asyncio import (_get_running_loop, ...)
except ImportError:
pass
else:
# Alias C implementations for testing purposes.
_c__get_running_loop = _get_running_loop
...
类似地,作为进一步的示例,对于
heapq
模块,我们在模块底部有以下内容,这将遮盖其上方定义的 Python 实现:
# If available, use C implementation
try:
from _heapq import *
except ImportError:
pass
...
同样对于
datetime
模块,我们有:
try:
from _datetime import *
except ImportError:
pass
它没有为同时可用的 Python + C 实现提供相同级别的“支持”,这个问题有更多详细信息。
并非所有 stdlib 模块都会隐藏所有内容,例如,
typing
仅尝试从 C 模块导入 _idfunc
,如果失败,则在 Python 中提供实现:
try:
from _typing import _idfunc
except ImportError:
def _idfunc(_, x):
return x
这个答案并不是对具有 C 对应项的 Python stdlib 模块的解释的详尽列表,但这个答案的目标是作为一个通用答案,说明 Python 的 stdlib 如何具有被 C 遮蔽的 Python 代码-based 模块,并且这种覆盖并不神奇,并且其具体操作方式肯定可以在受影响模块本身的 Python 代码中找到。