繁体   English   中英

Python多重处理过程不会终止

[英]Python mutiprocessing Process does not terminate

当我尝试使用多处理库在python中实现并行操作时,我看到某些进程不会以非直观的方式终止。

我的程序包括:

  • 队列,用于进程之间的数据传输
  • 用户进程,该进程使用通过队列接收的数据来计算内容
  • 两个制造商流程,它们生成数据并推送到队列

下面是一个简化的示例。 make_data生成随机数并推送到队列, use_data接收数据并计算平均值。 总共生成2 * 1000 = 2000个数字,并全部使用。 此代码按预期运行。 毕竟,所有进程都将终止,队列中没有任何数据。

import random
from multiprocessing import Process, Queue

q = Queue(maxsize=10000)
def make_data(q):
    for i in range(1000):
        x = random.random()
        q.put(x)
    print("final line of make data")

def use_data(q):
    i = 0
    res = 0.0
    while i < 2000:
        if q.empty():
            continue
        i += 1
        x = q.get()
        res = res*(i-1)/i + x/i
    print("iter %6d, avg = %.5f" % (i, res))

u = Process(target=use_data, args=(q,))
u.start()

p1 = Process(target=make_data, args=(q,))
p1.start()
p2 = Process(target=make_data, args=(q,))
p2.start()


u.join(timeout=10)
p1.join(timeout=10)
p2.join(timeout=10)
print(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

当我让制造商生成超出必要数据的东西时,情况发生了变化。 下面的代码与上面的代码的不同之处仅在于每个制造商生成5000个数据,因此并非所有数据都被使用。 运行此命令时,它会打印最后一行的消息,但是制造商进程永远不会终止(需要Ctrl-C停止)。

import random
from multiprocessing import Process, Queue

q = Queue(maxsize=10000)
def make_data(q):
    for i in range(5000):
        x = random.random()
        q.put(x)
    print("final line of make data")

def use_data(q):
    i = 0
    res = 0.0
    while i < 2000:
        if q.empty():
            continue
        i += 1
        x = q.get()
        res = res*(i-1)/i + x/i
    print("iter %6d, avg = %.5f" % (i, res))

u = Process(target=use_data, args=(q,))
u.start()

p1 = Process(target=make_data, args=(q,))
p1.start()
p2 = Process(target=make_data, args=(q,))
p2.start()


u.join(timeout=10)
p1.join(timeout=10)
p2.join(timeout=10)
print(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.49388
False True True 8000
# and never finish

在我看来,所有进程都将运行到最后,所以想知道为什么它们仍然存在。 有人可以帮助我了解这种现象吗?

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

将项目放入队列的子进程被卡住,试图将对象实际放入队列。

普通的,非多处理的Queue对象完全在单个进程的地址空间中实现。 在这种情况下, maxsize是在put()调用块之前可以入队的项目数。 但是,使用IPC机制实现了多处理Queue对象。 通常是管道。 并且OS管道可以将有限数量的字节排队(通常限制为8KB)。 因此,当use_data()进程仅在使2000个项目出队后终止时, make_data()进程就会阻塞,因为在退出时将本地排队的项目刷新到IPC中时,其IPC通道已满。 这意味着它们实际上并没有退出,因此, join()这些进程的尝试会无限期地阻塞。

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

for _ in range(4000):
    q.get()

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM