CPython:当 take_gil 函数调用 drop_gil 函数时会发生什么

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

我正在使用 perf 探针来分析多线程 Python 应用程序中的 GIL 争用,并且我找到了 take_gil 函数 调用 drop_gil 的序列,如以下捕获的 perf 数据的 perf 脚本转储所示:

       viztracer  5533 [003]  3220.317244274:         python:take_gil: (55fe99b0d01e)
       viztracer  5533 [003]  3220.317407813:         python:drop_gil: (55fe99b0cf20)
       viztracer  5533 [003]  3220.317412443: python:drop_gil__return: (55fe99b0cf20 <- 55fe99baaa9e)
       viztracer  5533 [003]  3220.317419189:         python:take_gil: (55fe99b0d01e)
       viztracer  5533 [003]  3220.317422951:         python:drop_gil: (55fe99b0cf20)
       viztracer  5533 [003]  3220.317425869: python:drop_gil__return: (55fe99b0cf20 <- 55fe99baaa9e)

发生这种情况的 CPython 代码中 take_gil 的相应部分如下所示:

if (_PyThreadState_MustExit(tstate)) {
    /* bpo-36475: If Py_Finalize() has been called and tstate is not
       the thread which called Py_Finalize(), exit immediately the
       thread.

       This code path can be reached by a daemon thread which was waiting
       in take_gil() while the main thread called
       wait_for_thread_shutdown() from Py_Finalize(). */
    MUTEX_UNLOCK(gil->mutex);
    /* tstate could be a dangling pointer, so don't pass it to
       drop_gil(). */
    drop_gil(interp, NULL, 1);
    PyThread_exit_thread();
}

我的问题是,这段代码是在什么条件下执行的?被调用的线程是否即将终止,如

PyThread_exit_thread()
所示。然而,perf 脚本转储表明线程 PID 5533 在之前在时间戳
3220.317419189
删除 GIL 后立即重新尝试在时间戳
3220.317412443
获取 GIL,因此线程 PID 5533 并未终止。

python cpython perf gil
1个回答
0
投票

此代码块仅与守护线程有关。如果没有其他活动的非守护线程,守护线程将不会使进程保持活动状态。请参阅https://docs.python.org/3/library/threading.html#threading.Thread.daemon

基本上最后一个非守护线程已经退出,python正在关闭过程中。此时不允许任何线程继续执行Python代码。从此时起,只需进行清理并确保进程不会挂起。请参阅文档上的此注释:

守护进程线程在关闭时突然停止。它们的资源(例如打开的文件、数据库事务等)可能无法正确释放。如果您希望线程正常停止,请将它们设置为非守护进程并使用合适的信号机制,例如事件。

这就是这段代码的含义,进程正在终止,但守护线程已尝试获取 GIL。这被拒绝,并且线程被

PyThread_exit_thread()
立即终止。这不太好,也不干净,但它确实确保了进程退出。

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