使用子进程模块是否释放python GIL?

时间:2014-04-29 15:33:11

标签: python multithreading subprocess python-multithreading gil

当通过Python的subprocess模块调用需要相对较长时间的Linux二进制文件时,是否会释放GIL?

我想并行化一些从命令行调用二进制程序的代码。使用线程(通过threadingmultiprocessing.pool.ThreadPool)或multiprocessing会更好吗?我的假设是,如果subprocess释放GIL,那么选择threading选项会更好。

3 个答案:

答案 0 :(得分:14)

  

当通过Python的subprocess模块调用需要相对较长时间的Linux二进制文件时,是否会释放GIL?

是的,它会在调用过程中释放Global Interpreter Lock (GIL)

正如您可能知道的那样,在POSIX平台上,subprocess在" raw"上提供了便利界面。来自forkexecvewaitpid的组件。

通过检查CPython 2.7.9源,forkexecve执行而不是释放GIL。但是,这些调用不会阻止,因此我们不希望释放GIL。

waitpid当然阻止,但我们看到它的实现确实使用ALLOW_THREADS宏放弃了GIL:

static PyObject *
posix_waitpid(PyObject *self, PyObject *args)
{
....
Py_BEGIN_ALLOW_THREADS
pid = waitpid(pid, &status, options);
Py_END_ALLOW_THREADS
....

这也可以通过从演示多线程python脚本调用一些长期运行的程序(如sleep来测试。

答案 1 :(得分:5)

GIL并不跨越多个流程。 subprocess.Popen开始一个新流程。如果它启动Python进程,那么它将拥有自己的GIL。

如果您只想并行运行某些Linux二进制文件,那么您不需要多个线程(或multiprocessing创建的进程):

from subprocess import Popen

# start all processes
processes = [Popen(['program', str(i)]) for i in range(10)]
# now all processes run in parallel

# wait for processes to complete
for p in processes:
    p.wait()

你可以use multiprocessing.ThreadPool to limit number of concurrently run programs

答案 2 :(得分:1)

由于subprocess用于运行可执行文件(它本质上是os.fork()os.execve()的包装器),因此使用它可能更有意义。您可以使用subprocess.Popen。类似的东西:

 import subprocess

 process = subprocess.Popen(["binary"])

这将作为一个单独的进程运行,因此不受GIL的影响。然后,您可以使用Popen.poll()方法检查子进程是否已终止:

if process.poll():
    # process has finished its work
    returncode = process.returncode

只需要确保不要调用等待的任何方法来完成其工作(例如Popen.communicate())以避免Python脚本阻塞。

正如this answer

中所述
  

multiprocessing用于在现有内部运行功能   (Python)代码,支持更灵活的通信   流程系列。 multiprocessing模块旨在提供   接口和功能非常类似于线程   允许CPython在多个CPU /核心之间扩展您的处理   尽管有GIL。

因此,考虑到您的用例,subprocess似乎是正确的选择。