ThreadedWorkerQueue.add_worker()
方法会阻塞,直到消耗Worker
为止。是否有一个很好的设计允许在ThreadedWorkerQueue
添加新工作人员而不阻止调用~.add_worker()
的线程,但是仍在使用条件?
这是一个简短的SSCCE:
import time
import threading
class Worker(object):
def work(self):
pass
class TimeWorker(Worker):
def __init__(self, seconds):
super(TimeWorker, self).__init__()
self.seconds = seconds
def work(self):
for i in xrange(self.seconds):
print "Working ... (%d)" % i
time.sleep(1)
class ThreadedWorkerQueue(threading.Thread):
def __init__(self):
super(ThreadedWorkerQueue, self).__init__()
self.condition = threading.Condition()
self.workers = []
self.running = False
def add_worker(self, worker):
with self.condition:
self.workers.append(worker)
self.condition.notify()
def stop(self):
with self.condition:
self.running = False
self.condition.notify()
self.join()
def consume(self):
if self.workers:
worker = self.workers.pop(0)
worker.work()
def run(self):
self.running = True
while True:
with self.condition:
if not self.running:
break
self.condition.wait()
self.consume()
def main():
queue = ThreadedWorkerQueue()
queue.start()
queue.add_worker(TimeWorker(3))
time.sleep(1)
tstart = time.time()
queue.add_worker(TimeWorker(2))
print "Blocked", time.time() - tstart, "seconds until worker was added."
queue.stop()
main()
好的,所以我最初的想法是在线程时可以唤醒条件 可以继续消费工人。这是基本原则 制片人/消费者设计,跳过连续轮询,真的只做了 当有工作要做时工作。
刚才,我有一个使用默认获取的锁的想法 在新员工被消费时释放。但我不确定这是不是 这样做的好方法。有人能发现问题(例如潜在的死锁)吗?
完整代码在GitHub上:https://github.com/NiklasRosenstein/async/blob/73828ecaa2990a71b63caf93c32f9cce5ec11d27/async.py#L686-L750
class ThreadedWorkerQueue(WorkerQueue, threading.Thread):
r""" This class implements the consumer design, introducing :class:`Worker`
objects to start working as soon as there are new workers available. Every
object adding Workers to this queue are the producers. """
def __init__(self):
WorkerQueue.__init__(self)
threading.Thread.__init__(self)
self.lock = threading.Lock()
def __del__(self):
if self.running:
self.stop()
warnings.warn("ThreadedWorkerQueue not stopped before its lost.")
def notify(self):
r""" Notify the ThreadedWorkerQueue that processing can be continued.
It is usually not necessary to call this method manually. """
try:
self.lock.release()
except (thread.error, RuntimeError):
pass
def stop(self, join=True, clear=False):
r""" Interrupt the thread in its doing, pausing the threads actions
until :meth:`start` is called again. All remaining workers are kept
alive unless *clear* is specified True. """
if clear: self.workers.clear()
self.running = False
self.notify()
if join: self.join()
def consume(self):
r""" Just like :meth:`WorkerQueue.work_off`, but doesn't override
the value of :prop:`running`. """
while self.workers:
worker = self.workers.popleft()
self.current = worker
worker.work()
self.current = None
# WorkerQueue
def add_worker(self, worker):
super(ThreadedWorkerQueue, self).add_worker(worker)
self.notify()
# threading.Thread
def start(self):
r""" Overrides :meth:`threading.Thread.start` to allow starting
the ThreadedWorkerQueue multiple times. """
threading.Thread.__init__(self)
return threading.Thread.start(self)
def run(self):
self.running = True
while True:
self.consume()
if not self.running: break
self.lock.acquire()
答案 0 :(得分:0)
......但仍在处理条件?
您不需要条件。 Python已经有一个完美的机制:Queue.Queue
。将ThreadedWorkerQueue.workers
从列表更改为Queue
,您无需担心条件,锁定,通知等问题。这将极大地简化您的代码。
您需要替换:
Queue
Queue.put
Queue.get
并摆脱with self.condition: ...
。
此外,从self.join()
内拨打stop()
并不是一个好习惯。把它留给调用线程。如果您需要停止多个线程,您需要先将它们全部停止,然后才将它们全部加入。