Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/278.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
Python处理进程不终止_Python_Multiprocessing - Fatal编程技术网

Python处理进程不终止

Python处理进程不终止,python,multiprocessing,Python,Multiprocessing,当我尝试用python和多处理库实现并行操作时,我看到一些进程并没有以非直观的方式终止 我的课程包括: 用于进程间数据传输的队列 一个用户进程,它使用通过队列接收的数据计算某些内容 两个maker进程,生成数据并推送到队列 下面是一个简化的例子make_data生成随机数并推送到队列,use_data接收数据并计算平均值。总共生成2*1000=2000个数字,并全部使用。此代码按预期运行。毕竟,所有进程都被终止,队列中没有留下任何数据 随机导入 从多处理导入进程,队列 q=队列(最大值=10

当我尝试用python和多处理库实现并行操作时,我看到一些进程并没有以非直观的方式终止

我的课程包括:

  • 用于进程间数据传输的队列
  • 一个用户进程,它使用通过队列接收的数据计算某些内容
  • 两个maker进程,生成数据并推送到队列
下面是一个简化的例子
make_data
生成随机数并推送到队列,
use_data
接收数据并计算平均值。总共生成2*1000=2000个数字,并全部使用。此代码按预期运行。毕竟,所有进程都被终止,队列中没有留下任何数据

随机导入
从多处理导入进程,队列
q=队列(最大值=10000)
def make_数据(q):
对于范围(1000)内的i:
x=random.random()
q、 put(x)
打印(“生成数据的最后一行”)
def使用_数据(q):
i=0
res=0.0
而我<2000:
如果q.empty():
持续
i+=1
x=q.get()
res=res*(i-1)/i+x/i
打印(“iter%6d,平均值=%.5f”%(i,res))
u=进程(目标=使用_数据,参数=(q,))
u、 开始()
p1=过程(目标=生成数据,参数=(q,))
p1.开始()
p2=进程(目标=生成数据,参数=(q,))
p2.start()
u、 加入(超时=10)
p1.加入(超时=10)
p2.加入(超时=10)
打印(u.is_alive()、p1.is_alive()、p2.is_alive()、q.qsize())
结果:

final line of make data
final line of make data
iter   2000, avg = 0.49655
False False False 0
final line of make data
final line of make data
iter   2000, avg = 0.49388
False True True 8000
# and never finish
当我让制造商产生超过必要的数据时,情况就发生了变化。 下面的代码与上面的不同之处在于,每个制造商生成5000个数据,因此并非所有数据都使用。运行时,它会打印最后一行的消息,但maker进程永远不会终止(需要
Ctrl-C
停止)

随机导入
从多处理导入进程,队列
q=队列(最大值=10000)
def make_数据(q):
对于范围(5000)内的i:
x=random.random()
q、 put(x)
打印(“生成数据的最后一行”)
def使用_数据(q):
i=0
res=0.0
而我<2000:
如果q.empty():
持续
i+=1
x=q.get()
res=res*(i-1)/i+x/i
打印(“iter%6d,平均值=%.5f”%(i,res))
u=进程(目标=使用_数据,参数=(q,))
u、 开始()
p1=过程(目标=生成数据,参数=(q,))
p1.开始()
p2=进程(目标=生成数据,参数=(q,))
p2.start()
u、 加入(超时=10)
p1.加入(超时=10)
p2.加入(超时=10)
打印(u.is_alive()、p1.is_alive()、p2.is_alive()、q.qsize())
结果:

final line of make data
final line of make data
iter   2000, avg = 0.49655
False False False 0
final line of make data
final line of make data
iter   2000, avg = 0.49388
False True True 8000
# and never finish
在我看来,所有进程都会一直运行到最后,所以我想知道为什么它们会保持活动状态。有人能帮我理解这个现象吗


我在miniconda发行版的
python 3.6.6
上运行了这个程序。

将项目放入队列的子进程在实际将对象放入队列时遇到了问题

正常的、非多处理的
队列
对象完全在单个进程的地址空间中实现。在这种情况下,
maxsize
是在
put()
调用块之前可以排队的项目数。但多处理
队列
对象是使用IPC机制实现的;通常是一根管子。操作系统管道可以对有限数量的字节进行排队(典型限制为8KB)。因此,当您的
use\u data()
进程在2000个项目退出队列后终止时,
make\u data()
进程会阻塞,因为在退出时将本地排队的项目刷新到IPC时,它们的IPC通道已满。这意味着它们实际上不会退出,因此尝试
join()
这些进程会无限期地阻塞

实际上,您已经创建了一个死锁。发生这种情况的确切阈值取决于IPC通道可以缓冲多少数据。例如,在我的一台Linux服务器上,您的第二个示例在
u.join()

稍微减小该范围(例如,至3990)会产生间歇性挂起。将范围缩小得更多(例如,至3500)将始终挂起,因为至少有一个进程将数据填充到队列块中,同时将其项刷新到IPC通道中


这个故事的教训是什么?在尝试等待进程终止之前,请始终完全排空多处理队列。

Official document有提示。请记住,将项目放入队列的进程将在终止之前等待,直到“feeder”线程将所有缓冲项目馈送到底层管道。(子进程可以调用队列的cancel_join_thread()方法以避免此行为。)这意味着,无论何时使用队列,您都需要确保在加入流程之前,已放入队列的所有项目最终都将被删除。”另外,在现实世界中,您通常不知道有多少项目将填充到队列中。处理这个问题的方法是让每个子进程在退出队列时向队列中填充一个哨兵值,该值可以与实际数据区分开来。然后,读者检查哨兵,当它被看到时,“加入”这个过程并忘记它。或者,在调用
u.join()
之后,在
p1
p2
上调用
terminate()
方法。感谢您的解释。我想它澄清了我的情况,引导我更深入地理解。