【问题标题】:multiprocessing.Queue deadlocks after "reader" process deathmultiprocessing.Queue 在“reader”进程死亡后死锁
【发布时间】:2014-02-16 11:04:03
【问题描述】:

我一直在玩多处理包,并注意到在以下情况下读取队列可能会死锁:

  1. “阅读器”进程正在使用get超时 > 0:

    self.queue.get(timeout=3)
    
  2. “reader”死了,而get 由于超时而阻塞。

在该队列被永久锁定之后。

应用程序演示问题

我创建了两个子进程“Worker”(放入队列)和“Receiver”(从队列中获取)。父进程还会定期检查他的孩子是否are alive 并在需要时启动新的孩子。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import multiprocessing
import procname
import time

class Receiver(multiprocessing.Process):
    ''' Reads from queue with 3 secs timeout '''

    def __init__(self, queue):
        multiprocessing.Process.__init__(self)
        self.queue = queue

    def run(self):
        procname.setprocname('Receiver')
        while True:
            try:
                msg = self.queue.get(timeout=3)
                print '<<< `{}`, queue rlock: {}'.format(
                    msg, self.queue._rlock)
            except multiprocessing.queues.Empty:
                print '<<< EMPTY, Queue rlock: {}'.format(
                    self.queue._rlock)
                pass


class Worker(multiprocessing.Process):
    ''' Puts into queue with 1 sec sleep '''

    def __init__(self, queue):
        multiprocessing.Process.__init__(self)
        self.queue = queue

    def run(self):
        procname.setprocname('Worker')
        while True:
            time.sleep(1)
            print 'Worker: putting msg, Queue size: ~{}'.format(
                self.queue.qsize())
            self.queue.put('msg from Worker')


if __name__ == '__main__':
    queue = multiprocessing.Queue()

    worker = Worker(queue)
    worker.start()

    receiver = Receiver(queue)
    receiver.start()

    while True:
        time.sleep(1)
        if not worker.is_alive():
            print 'Restarting worker'
            worker = Worker(queue)
            worker.start()
        if not receiver.is_alive():
            print 'Restarting receiver'
            receiver = Receiver(queue)
            receiver.start()

进程树在 ps 中的样子

bash
 \_ python queuetest.py
     \_ Worker
     \_ Receiver

控制台输出

$ python queuetest.py
Worker: putting msg, Queue size: ~0
<<< `msg from Worker`, queue rlock: <Lock(owner=None)>
Worker: putting msg, Queue size: ~0
<<< `msg from Worker`, queue rlock: <Lock(owner=None)>
Restarting receiver                        <-- killed Receiver with SIGTERM
Worker: putting msg, Queue size: ~0
Worker: putting msg, Queue size: ~1
Worker: putting msg, Queue size: ~2
<<< EMPTY, Queue rlock: <Lock(owner=SomeOtherProcess)>
Worker: putting msg, Queue size: ~3
Worker: putting msg, Queue size: ~4
Worker: putting msg, Queue size: ~5
<<< EMPTY, Queue rlock: <Lock(owner=SomeOtherProcess)>
Worker: putting msg, Queue size: ~6
Worker: putting msg, Queue size: ~7

有没有办法绕过这个?将get_nowait 与睡眠结合使用似乎是某种解决方法,但它不会“按时”读取数据。

系统信息

$ uname -sr
Linux 3.11.8-200.fc19.x86_64

$ python -V
Python 2.7.5

In [3]: multiprocessing.__version__
Out[3]: '0.70a1'

“它只是工作”解决方案

在写这个问题时,我对 Receiver 类做了一些愚蠢的修改:

class Receiver(multiprocessing.Process):

    def __init__(self, queue):
        multiprocessing.Process.__init__(self)
        self.queue = queue

    def run(self):
        procname.setprocname('Receiver')
        while True:
            time.sleep(1)
            while True:
                try:
                    msg = self.queue.get_nowait()
                    print '<<< `{}`, queue rlock: {}'.format(
                        msg, self.queue._rlock)
                except multiprocessing.queues.Empty:
                    print '<<< EMPTY, Queue rlock: {}'.format(
                        self.queue._rlock)
                    break

但对我来说似乎不是很好。

【问题讨论】:

标签: python python-2.7 queue multiprocessing


【解决方案1】:

这可能是因为 Queue.get() 中的 *not_empty.release()* 从未发生过(进程已被终止)。您是否尝试在 Receiver 中捕获 TERM 信号并在退出前释放 Queue 互斥锁?

【讨论】:

  • 你的意思是_rlock.release()(这个用在Queue.get AFAIK中)?不,我没有尝试捕捉任何信号,因为我更多地考虑接收器由于错误而不是确实可以处理的“温和”信号而崩溃。
  • 正如另一个answer 指出的那样,正确的解决方案是使用“强大的互斥锁”或“命名信号量”。我建议您报告多处理库中的错误。
猜你喜欢
  • 2018-02-22
  • 1970-01-01
  • 1970-01-01
  • 2011-12-09
  • 1970-01-01
  • 2020-03-30
  • 2013-12-12
  • 2015-09-02
  • 2012-12-11
相关资源
最近更新 更多