copy.wait()
持有 GIL 也是我的第一个怀疑。但是,在我的系统上似乎并非如此(wait()
调用不会阻止其他线程继续进行)。
你是对的,copy.wait()
最终以os.waitpid()
. 后者在我的 Linux 系统上看起来像这样:
PyDoc_STRVAR(posix_waitpid__doc__,
"waitpid(pid, options) -> (pid, status)\n\n\
Wait for completion of a given child process.");
static PyObject *
posix_waitpid(PyObject *self, PyObject *args)
{
pid_t pid;
int options;
WAIT_TYPE status;
WAIT_STATUS_INT(status) = 0;
if (!PyArg_ParseTuple(args, PARSE_PID "i:waitpid", &pid, &options))
return NULL;
Py_BEGIN_ALLOW_THREADS
pid = waitpid(pid, &status, options);
Py_END_ALLOW_THREADS
if (pid == -1)
return posix_error();
return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status));
}
这清楚地释放了 GIL,而它在 POSIX 中被阻止waitpid
。
当进程挂起时,我会尝试附加gdb
到python
进程以查看线程在做什么。也许这会提供一些想法。
编辑这是多线程 Python 进程的样子gdb
:
(gdb) info threads
11 Thread 0x7f82c6462700 (LWP 30865) 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
10 Thread 0x7f82c5c61700 (LWP 30866) 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
9 Thread 0x7f82c5460700 (LWP 30867) 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
8 Thread 0x7f82c4c5f700 (LWP 30868) 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
7 Thread 0x7f82c445e700 (LWP 30869) 0x00000000004a3c37 in PyEval_EvalFrameEx ()
6 Thread 0x7f82c3c5d700 (LWP 30870) 0x00007f82c7676dcd in sem_post () from /lib/libpthread.so.0
5 Thread 0x7f82c345c700 (LWP 30871) 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
4 Thread 0x7f82c2c5b700 (LWP 30872) 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
3 Thread 0x7f82c245a700 (LWP 30873) 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
2 Thread 0x7f82c1c59700 (LWP 30874) 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
* 1 Thread 0x7f82c7a7c700 (LWP 30864) 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
在这里,除了两个之外的所有线程都在等待 GIL。典型的堆栈跟踪如下所示:
(gdb) thread 11
[Switching to thread 11 (Thread 0x7f82c6462700 (LWP 30865))] #0 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
(gdb) where
#0 0x00007f82c7676b50 in sem_wait () from /lib/libpthread.so.0
#1 0x00000000004d4498 in PyThread_acquire_lock ()
#2 0x00000000004a2f3f in PyEval_EvalFrameEx ()
#3 0x00000000004a9671 in PyEval_EvalCodeEx ()
...
hex(t.ident)
您可以通过在 Python 代码中打印来确定哪个线程是哪个线程t
,threading.Thread
对象在哪里。在我的系统上,这与gdb
( 0x7f82c6462700
et al) 中看到的线程 ID 相匹配。