源码位置:cpython\Python\pylifecycle.c

一._PyRuntime_Initialize
这段代码是Python解释器生命周期管理的关键部分,负责初始化Python运行时环境。该函数确保了Python解释器在启动过程中拥有正确初始化的运行时环境,这是Python能够正常工作的基础。
staticint runtime_initialized = 0;
PyStatus
_PyRuntime_Initialize(void)
{
/* XXX We only initialize once in the process, which aligns with
the static initialization of the former globals now found in
_PyRuntime. However, _PyRuntime *should* be initialized with
every Py_Initialize() call, but doing so breaks the runtime.
This is because the runtime state is not properly finalized
currently. */
if (runtime_initialized) {
return _PyStatus_OK();
}
runtime_initialized = 1;
return _PyRuntimeState_Init(&_PyRuntime);
}
1.单次初始化机制
-
函数通过检查
runtime_initialized
标志确保运行时只被初始化一次 -
如果已经初始化过,直接返回成功状态
2.初始化过程
-
当首次调用时,设置
runtime_initialized = 1
-
然后调用
_PyRuntimeState_Init(&_PyRuntime)
进行实际的运行时状态初始化
3.设计约束
-
注释中指出了一个已知问题:理想情况下,
_PyRuntime
应该在每次调用Py_Initialize()
时重新初始化 -
但目前这样做会导致运行时崩溃,因为运行时状态没有被正确地终结
-
这解释了为什么函数使用静态标志确保只初始化一次
二._PyRuntimeState_Init
源码位置:cpython\Python\pystate.c
这个函数负责初始化 Python 运行时状态,是 Python 启动过程中的关键步骤。这个函数是 Python 解释器启动过程中的关键部分,确保运行时环境正确初始化,为后续的解释器操作提供基础设施。它处理了运行时状态的创建、重置和配置,特别是在多次初始化/终止 Python 解释器的场景中,保持了关键状态的连续性。
PyStatus
_PyRuntimeState_Init(_PyRuntimeState *runtime)
{
/* We preserve the hook across init, because there is
currently no public API to set it between runtime
initialization and interpreter initialization. */
void *open_code_hook = runtime->open_code_hook;
void *open_code_userdata = runtime->open_code_userdata;
_Py_AuditHookEntry *audit_hook_head = runtime->audit_hooks.head;
// bpo-42882: Preserve next_index value if Py_Initialize()/Py_Finalize()
// is called multiple times.
Py_ssize_t unicode_next_index = runtime->unicode_state.ids.next_index;
if (runtime->_initialized) {
// Py_Initialize() must be running again.
// Reset to _PyRuntimeState_INIT.
memcpy(runtime, &initial, sizeof(*runtime));
// Preserve the cookie from the original runtime.
memcpy(runtime->debug_offsets.cookie, _Py_Debug_Cookie, 8);
assert(!runtime->_initialized);
}
PyStatus status = _PyTime_Init(&runtime->time);
if (_PyStatus_EXCEPTION(status)) {
return status;
}
if (gilstate_tss_init(runtime) != 0) {
_PyRuntimeState_Fini(runtime);
return _PyStatus_NO_MEMORY();
}
if (PyThread_tss_create(&runtime->trashTSSkey) != 0) {
_PyRuntimeState_Fini(runtime);
return _PyStatus_NO_MEMORY();
}
init_runtime(runtime, open_code_hook, open_code_userdata, audit_hook_head,
unicode_next_index);
return _PyStatus_OK();
}
1.保存关键状态
首先保存几个重要的运行时组件,以便在重置运行时状态后能够恢复它们:
-
open_code_hook
和open_code_userdata
:用于处理代码文件打开的钩子 -
audit_hook_head
:审计钩子链表头 -
unicode_next_index
:Unicode ID 索引值(在多次调用 Py_Initialize/Py_Finalize 时需要保留)
2.重新初始化检查
-
如果
runtime->_initialized
为真,说明Py_Initialize()
正在再次运行 -
此时通过
memcpy
将运行时状态重置为初始状态(_PyRuntimeState_INIT
) -
同时保留原始运行时的调试 cookie
3.时间模块初始化
-
调用
_PyTime_Init
初始化运行时的时间组件 -
如果初始化失败,立即返回错误状态
4.线程状态存储初始化
-
调用
gilstate_tss_init
初始化线程特定存储,用于 GIL 状态管理 -
如果失败,清理资源并返回内存不足错误
5.垃圾回收 TSS 初始化
-
创建
trashTSSkey
,用于线程特定的垃圾回收 -
如果失败,清理资源并返回内存不足错误
6.完成运行时初始化
-
调用
init_runtime
函数,传入之前保存的钩子和索引值 -
设置运行时状态标记
_initialized
7.返回成功状态
-
如果所有步骤都成功,返回 _PyStatus_OK()
三.init_runtime
源码位置:cpython\Python\pystate.c
这个init_runtime
函数负责初始化Python解释器的运行时状态。它是Python启动过程中的关键环节,设置了各种重要的运行时参数和状态。
staticvoid
init_runtime(_PyRuntimeState *runtime,
void *open_code_hook, void *open_code_userdata,
_Py_AuditHookEntry *audit_hook_head,
Py_ssize_t unicode_next_index)
{
assert(!runtime->preinitializing);
assert(!runtime->preinitialized);
assert(!runtime->core_initialized);
assert(!runtime->initialized);
assert(!runtime->_initialized);
runtime->open_code_hook = open_code_hook;
runtime->open_code_userdata = open_code_userdata;
runtime->audit_hooks.head = audit_hook_head;
PyPreConfig_InitPythonConfig(&runtime->preconfig);
// Set it to the ID of the main thread of the main interpreter.
runtime->main_thread = PyThread_get_thread_ident();
runtime->unicode_state.ids.next_index = unicode_next_index;
#ifdefined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
_Py_EmscriptenTrampoline_Init(runtime);
#endif
runtime->_initialized = 1;
}
1.状态检查
通过一系列断言确保运行时状态尚未被初始化,防止重复初始化:
assert(!runtime->preinitializing);
assert(!runtime->preinitialized);
assert(!runtime->core_initialized);
assert(!runtime->initialized);
assert(!runtime->_initialized);
2.设置代码钩子
这些钩子函数用于打开和处理Python代码文件,是实现自定义代码加载机制的关键。
runtime->open_code_hook = open_code_hook;
runtime->open_code_userdata = open_code_userdata;
3.设置审计钩子
这是Python安全审计系统的一部分,允许监控解释器的关键操作。
runtime->audit_hooks.head = audit_hook_head;
4.初始化预配置
设置默认的Python预配置选项。
PyPreConfig_InitPythonConfig(&runtime->preconfig);
5.记录主线程ID
将当前线程标记为主线程,这对后续的线程管理和GIL操作很重要。
runtime->main_thread = PyThread_get_thread_ident();
6.设置Unicode状态
初始化Unicode对象ID的下一个可用索引。
runtime->unicode_state.ids.next_index = unicode_next_index;
7.Emscripten特殊处理
为WebAssembly环境提供支持。
8.标记初始化完成
设置标志表示运行时已成功初始化。
runtime->_initialized = 1;
这个函数是Python启动过程的基础,为后续的解释器操作和线程管理奠定了基础。它处理的是底层运行时状态,而不是直接初始化Python解释器的所有部分。
参考文献
[0] _PyRuntime_Initialize函数解析:https://z0yrmerhgi8.feishu.cn/wiki/C010wBP0SiCATiklNH0csmdmn1g
[1] Python初始化配置:https://docs.python.org/zh-cn/3.14/c-api/init_config.html
[2] Initialization, Finalization, and Threads(初始化,最终化和线程):https://docs.python.org/zh-cn/3.14/c-api/init.html#
知识星球服务内容:Dify源码剖析及答疑,Dify对话系统源码,NLP电子书籍报告下载,公众号所有付费资料。加微信buxingtianxia21进NLP工程化资料群。
(文:NLP工程化)