python多处理队列put()和get()

时间:2015-05-02 21:28:49

标签: python linux queue multiprocessing blocking

我在python 2.7(在linux下)编写了一个类,它使用多个进程异步操作数据库。使用multiprocessing.Queue.put()multiprocessing.Queue.get()时我遇到了一种非常奇怪的阻止行为,我无法解释。

以下是我所做的简化版本:

from multiprocessing import Process, Queue

class MyDB(object):  

    def __init__(self):
        self.inqueue = Queue()

        p1 = Process(target = self._worker_process, kwargs={"inqueue": self.inqueue})
        p1.daemon = True
        started = False
        while not started:
            try:
                p1.start()
                started = True
            except:
                time.sleep(1)  

        #Sometimes I start a same second process but it makes no difference to my problem 
        p2 = Process(target = self._worker_process, kwargs={"inqueue": self.inqueue})
        #blahblah... (same as above)

    @staticmethod
    def _worker_process(inqueue):
        while True:
            #--------------this blocks depite data having arrived------------

            op = inqueue.get(block = True)
            #do something with specified operation

            #---------------problem area end--------------------
            print "if this text gets printed, the problem was solved"

    def delete_parallel(self, key, rawkey = False):
        someid = ...blahblah
        #--------------this section blocked when I was posting the question but for unknown reasons it's fine now
        self.inqueue.put({"optype": "delete", "kwargs": {"key":key, "rawkey":rawkey}, "callid": someid}, block = True) 
        #--------------problem area end----------------
        print "if you see this text, there was no blocking or block was released"

如果我在测试中运行上面的代码(我在delete_parallel对象上调用MyDB),那么一切正常,但如果我在整个应用程序的上下文中运行它(导入其他东西) ,包容性pygtk)奇怪的事情发生:

由于某种原因,self.inqueue.get阻止并且永远不会释放,尽管self.inqueue在其缓冲区中有数据。当我改为调用self.inqueue.get(block = False, timeout = 1)时,尽管队列包含数据,但是通过提升Queue.Empty来完成调用。 qsize()返回1(建议数据存在),而empty()返回True(表示没有数据)。

现在很明显,我的应用程序中必须存在其他某些内容,它会导致self.inqueue无法通过获取某些内部信号量而无法使用。但是,我不知道该寻找什么。一旦达到阻塞信号量,Eclipse dubugging就变得毫无用处。

编辑8 (清理并总结我以前的编辑)上次遇到类似的问题时,结果发现pygtk正在劫持全局解释器锁,但我通过调用{{1在我打电话之前。这个问题可能有关系吗?

当我在gobject.threads_init()方法之后引入print "successful reception"并在终端中执行我的应用程序时,首先会发生相同的行为。当我按CTRL + D终止时,我突然得到字符串"成功接收" inbetween消息。这看起来像一些其他进程/线程被终止并释放锁定阻塞get()进程的锁。

由于卡住的进程稍后终止,我仍然会看到该消息。什么样的过程可以从外部弄乱这样的队列? get()只能在我班级内访问。

现在它似乎归结为这个队列,尽管有数据存在但仍无法返回任何内容:

defect queue

self.inqueue方法在尝试从某个内部管道接收实际数据时似乎卡住了。调试器挂起之前的最后一行是:

get()

位于res = self._recv() 内 跟踪这个内部python的东西,我找到了分配 multiprocessing.queues.get()self._recv = self._reader.recv

编辑9 我目前正试图追捕导致它的导入。我的应用程序非常复杂,有数百个类,每个类导入很多其他类,所以这是一个非常痛苦的过程。我找到了第一个候选类,当我跟踪它的所有导入时使用3个不同的self._reader, self._writer = Pipe(duplex=False)个实例(但据我所知,它在任何时候都不能访问MyDB。奇怪的是,它基本上只是一个包装器,并且包装类在单独导入时工作得很好。这也意味着它使用MyDB.inqueue而不冻结。一旦我导入包装器(导入该类),我就会遇到阻塞问题。

我开始通过逐步重用旧代码来重写包装器。我每次引入几行新行时都要测试,直到我希望看到哪一行会导致问题返回。

1 个答案:

答案 0 :(得分:0)

queue.Queue使用内部线程来维护其状态。如果您使用GTK,那么它将破坏这些线程。因此,您需要致电gobject.init_threads()

应该注意,qsize()仅返回队列的近似大小。实际大小可以是介于0和qsize()返回的值之间的任何位置。