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()
...
你可以找出哪些线程是由你的Python代码,其中t
是threading.Thread
对象打印hex(t.ident)
。在我的系统中,这与在gdb
(0x7f82c6462700
等)中看到的线程ID匹配。
来源
2011-06-03 10:11:09
NPE
所以,我一直等到我的程序被卡住了 - 我可以从日志中知道,因为我停止收到调试消息。然后我尝试用gdb附加到它。这花了一些时间,我猜测我的程序将“正常”卡住的时间长度。当gdb最终回到我身边时,我看到了所有在sem_wait中的线程,除了在waitpid()中的线程和在clone()中的线程(这可能是我的主线程,它正在创建新线程)。 做sem_wait的优势意味着一切都只是在等待GIL? – 2011-06-03 10:47:02
@Igor:你的评论的第一部分暗示了比Python的GIL更低的瓶颈。我会首先检查'top'和'vmstat'中的进程和系统来监视内存/ CPU使用率,分页,I/O等事情,然后在程序无法进展的时间和期间。 – NPE 2011-06-03 10:50:49