Python 2.6 multiprocessing.Queue与线程兼容?

时间:2008-12-05 00:45:05

标签: python multiprocessing python-2.6

我正在使用Python 2.6中的新多处理模块进行实验。我正在创建几个进程,每个进程都有自己的multiprocessor.JoinableQueue实例。每个进程生成一个或多个工作线程(threading.Thread的子类),它们共享JoinableQueue实例(通过每个Thread的__init__方法传入)。它似乎通常可以工作,但偶尔和不可预测的失败,出现以下错误:

  File "C:\Documents and Settings\Brian\Desktop\testscript.py", line 49, in run
    self.queue.task_done()
  File "C:\Python26\lib\multiprocessing\queues.py", line 293, in task_done
    raise ValueError('task_done() called too many times')
ValueError: task_done() called too many times

我的队列get()和task_done()调用是在彼此之后,因此它们应该是相等的。有趣的是,这似乎只有在get()和task_done()之间完成的工作非常快时才会发生。插入一个小time.sleep(0.01)似乎可以缓解这个问题。

任何想法是怎么回事?我可以使用带有线程的多处理器队列而不是更传统的(Queue.Queue)吗?

谢谢!

-Brian

4 个答案:

答案 0 :(得分:4)

我还没有在2.6中尝试过多处理,但我在pyprocessing中玩了很多(因为它在2.5中被称为)。

我可以看到你正在寻找许多进程,每个进程分别产生一组线程。

由于您正在使用多处理模块,我建议使用多进程而不是多线程方法,您将遇到更少的问题,如死锁等。

创建一个队列对象。 http://pyprocessing.berlios.de/doc/queue-objects.html

要创建多进程环境,请使用池:http://pyprocessing.berlios.de/doc/pool-objects.html,它将为您管理工作进程。然后,您可以将异步/同步应用于worker,并且还可以根据需要为每个worker添加回调。但请记住,回调是一个公共代码块,它应该立即返回(如文档中所述)

其他一些信息: 如果需要,请创建管理器http://pyprocessing.berlios.de/doc/manager-objects.html以管理对队列对象的访问。您必须为此共享队列对象。但优点是,一旦共享和管理,您就可以通过创建代理对象来访问整个网络中的此共享队列。这将使您能够将集中式共享队列对象的方法作为(显然)任何网络节点上的本机方法。

这是文档中的代码示例

可以在一台计算机上运行管理服务器,并让客户端从其他计算机上使用它(假设所涉及的防火墙允许它)。 运行以下命令会为远程客户端可以使用的共享队列创建服务器:

>>> from processing.managers import BaseManager, CreatorMethod
>>> import Queue
>>> queue = Queue.Queue()
>>> class QueueManager(BaseManager):
...     get_proxy = CreatorMethod(callable=lambda:queue, typeid='get_proxy')
...
>>> m = QueueManager(address=('foo.bar.org', 50000), authkey='none')
>>> m.serve_forever()

一个客户端可以按如下方式访问服务器:

>>> from processing.managers import BaseManager, CreatorMethod
>>> class QueueManager(BaseManager):
...     get_proxy = CreatorMethod(typeid='get_proxy')
...
>>> m = QueueManager.from_address(address=('foo.bar.org', 50000), authkey='none')
>>> queue = m.get_proxy()
>>> queue.put('hello')

如果您坚持使用安全的线程,PEP371(多处理)会引用此http://code.google.com/p/python-safethread/

答案 1 :(得分:2)

您应该将Queue对象作为目标参数传递。

来自multiprocessing's documentation的示例:

from multiprocessing import Process, Queue

def f(q):
    q.put([42, None, 'hello'])

 if __name__ == '__main__':
     q = Queue()
     p = Process(target=f, args=(q,))
     p.start()
     print q.get()    # prints "[42, None, 'hello']"
     p.join()
  

队列是线程和进程安全的。

答案 2 :(得分:1)

您可能遇到此错误:

http://bugs.python.org/issue4660

答案 3 :(得分:-1)

感谢您的快速回复。我正在将multiprocessing.Queue实例作为参数传递给每个进程,如图所示。失败似乎发生在线程中。我通过子类化threading.Thread并将队列传递给每个线程实例的' init '方法来创建它们。这似乎是将队列传递给线程子类的可接受方式。我唯一认为多处理队列可能与线程不兼容(尽管它们应该是线程安全的)。