Python Asyncio源码分析:为什么Python中的`_get_running_loop`执行的是C实现而不是Python实现?

问题描述 投票:0回答:1

我一直在探索

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 python-asyncio cpython event-loop
1个回答
0
投票

一般来说,就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 代码中找到。

© www.soinside.com 2019 - 2024. All rights reserved.