Я пытаюсь реализовать многопоточность шаблона производителя-потребителя, используя Queue.Queue в Python 2.7. Я пытаюсь выяснить, как заставить потребителей, т.е. Рабочие потоки, остановиться, как только будет завершена вся необходимая работа.
См. Второй комментарий Мартина Джеймса к этому ответу: qaru.site/info/5751624/...
Отправьте задание "Я закончен", инструктируя потоки пулов завершить работу. Любой поток, который получает такую задачу, требует его, а затем совершает самоубийство.
Но это не работает для меня. См. Следующий код, например.
import Queue
import threading
import time
def worker(n, q):
# n - Worker ID
# q - Queue from which to receive data
while True:
data = q.get()
print 'worker', n, 'got', data
time.sleep(1) # Simulate noticeable data processing time
q.task_done()
if data == -1: # -1 is used to indicate that the worker should stop
# Requeue the exit indicator.
q.put(-1)
# Commit suicide.
print 'worker', n, 'is exiting'
break
def master():
# master() sends data to worker() via q.
q = Queue.Queue()
# Create 3 workers.
for i in range(3):
t = threading.Thread(target=worker, args=(i, q))
t.start()
# Send 10 items to work on.
for i in range(10):
q.put(i)
time.sleep(0.5)
# Send an exit indicator for all threads to consume.
q.put(-1)
print 'waiting for workers to finish ...'
q.join()
print 'done'
master()
Эта программа зависает после того, как все три сотрудника прочитали индикатор выхода, т. -1
из очереди, потому что каждый рабочий запрашивает -1
перед выходом, поэтому очередь никогда не становится пустой, а q.join()
никогда не возвращается.
Я придумал следующее, но уродливое решение, в котором я посылаю индикатор -1
для каждого рабочего через очередь, чтобы каждый работник мог видеть это и совершать самоубийство. Но тот факт, что я должен отправить индикатор выхода для каждого работника, кажется немного уродливым.
import Queue
import threading
import time
def worker(n, q):
# n - Worker ID
# q - Queue from which to receive data
while True:
data = q.get()
print 'worker', n, 'got', data
time.sleep(1) # Simulate noticeable data processing time
q.task_done()
if data == -1: # -1 is used to indicate that the worker should stop
print 'worker', n, 'is exiting'
break
def master():
# master() sends data to worker() via q.
q = Queue.Queue()
# Create 3 workers.
for i in range(3):
t = threading.Thread(target=worker, args=(i, q))
t.start()
# Send 10 items to work on.
for i in range(10):
q.put(i)
time.sleep(0.5)
# Send one stop indicator for each worker.
for i in range(3):
q.put(-1)
print 'waiting for workers to finish ...'
q.join()
print 'done'
master()
У меня есть два вопроса.
- Может ли работать метод отправки одного индикатора выхода для всех потоков (как объясняется во втором комментарии qaru.site/info/5751624/... от Martin James)?
- Если ответ на предыдущий вопрос "Нет", есть ли способ решить проблему таким образом, что мне не нужно отправлять отдельный индикатор выхода для каждого рабочего потока?