我正在使用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
答案 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)
您可能遇到此错误:
答案 3 :(得分:-1)
感谢您的快速回复。我正在将multiprocessing.Queue实例作为参数传递给每个进程,如图所示。失败似乎发生在线程中。我通过子类化threading.Thread并将队列传递给每个线程实例的' init '方法来创建它们。这似乎是将队列传递给线程子类的可接受方式。我唯一认为多处理队列可能与线程不兼容(尽管它们应该是线程安全的)。