Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Popen在Python 2.7中不返回_Python_Multithreading_Python 2.7_Process - Fatal编程技术网

Popen在Python 2.7中不返回

Popen在Python 2.7中不返回,python,multithreading,python-2.7,process,Python,Multithreading,Python 2.7,Process,我正在用Python开发一个进程调度器。其思想是从主函数创建几个线程,并在每个线程中启动一个外部进程。外部进程应该继续运行,直到它完成或者主线程决定停止它(通过发送kill信号),因为进程的CPU时间限制被超过 问题是,Popen调用有时会阻塞并无法返回。这段代码在我的系统(Ubuntu 14.04.3 LTS)上以大约50%的概率再现了这个问题: 输出表明只有3个Popen()调用返回: Run subprocess: /bin/cat Run subprocess: /bin/cat Run

我正在用Python开发一个进程调度器。其思想是从主函数创建几个线程,并在每个线程中启动一个外部进程。外部进程应该继续运行,直到它完成或者主线程决定停止它(通过发送kill信号),因为进程的CPU时间限制被超过

问题是,
Popen
调用有时会阻塞并无法返回。这段代码在我的系统(Ubuntu 14.04.3 LTS)上以大约50%的概率再现了这个问题:

输出表明只有3个
Popen()
调用返回:

Run subprocess: /bin/cat
Run subprocess: /bin/cat
Run subprocess: /bin/cat
Run subprocess: /bin/cat
 started a process
started a process
started a process
all threads started
但是,运行
ps
表明所有四个进程实际上都已启动

使用Python3.4时不会出现这个问题,但我希望保持Python2.7的兼容性

编辑:如果我在启动每个后续线程之前添加一些延迟,问题也会消失

编辑2:我做了一些调查,阻塞是由
subprocess.py
模块中的第1308行引起的,该行试图从父进程中的管道执行一些读取:

   data = _eintr_retry_call(os.read, errpipe_read, 1048576)

Python2.7的
子进程
模块中存在一些bug,当从多个线程调用
Popen
构造函数时,这些bug可能导致死锁。它们在Python的更高版本3.2+IIRC中得到了修复

您可能会发现,使用Python 3.2/3.3的
子流程
模块的
子流程32
后端口可以解决您的问题


*我无法找到实际错误报告的链接,但最近在处理类似问题时遇到了它。

我可以重现您描述的行为。但是,您的示例中存在一些问题:首先,在进入while循环之前添加一个输出,然后在
Popen()
之后立即添加输出。这不会改变任何事情,但会让事情变得更清楚。然后,就可以访问
Process.counter
,这可能会导致竞态条件,所以请删除它,但它也不会改变问题。然后,有一件事肯定是错的,那就是
finally
子句中的
return-retcode
,因为
finally
子句即使在
return
时也会执行,但仍然没有更改。有趣的问题@UlrichEckhardt我根据您的建议更新了代码,并在最后添加了更多的信息。有趣的是,我认为我有相同的问题,因为我使用多线程与调制解调器通信,有时它只是挂起:
   data = _eintr_retry_call(os.read, errpipe_read, 1048576)