То, что вы ищете, - это шаблон "производитель / потребитель".
Базовый пример потоковой передачи
Вот базовый пример использования модуля потоковой передачи (вместо многопроцессорной обработки)
import threading
import Queue
import sys
def do_work(in_queue, out_queue):
while True:
item = in_queue.get()
result = item
out_queue.put(result)
in_queue.task_done()
if __name__ == "__main__":
work = Queue.Queue()
results = Queue.Queue()
total = 20
for i in xrange(4):
t = threading.Thread(target=do_work, args=(work, results))
t.daemon = True
t.start()
for i in xrange(total):
work.put(i)
work.join()
for i in xrange(total):
print results.get()
sys.exit()
Вы бы не стали делиться файловым объектом с потоками. Вы могли бы произвести для них работу, снабдив очередь строками данных. Затем каждый поток брал строку, обрабатывал ее и затем возвращал в очередь.
В модуль многопроцессорной обработки встроены некоторые более продвинутые средства для обмена данными, такие как списки и особый вид очереди . Есть компромиссы между использованием многопроцессорности и потоков, и это зависит от того, привязана ли ваша работа к процессору или к вводу-выводу.
Базовая многопроцессорная обработка. Пример пула
Вот действительно простой пример многопроцессорного пула
from multiprocessing import Pool
def process_line(line):
return "FOO: %s" % line
if __name__ == "__main__":
pool = Pool(4)
with open('file.txt') as source_file:
results = pool.map(process_line, source_file, 4)
print results
Пул - это удобный объект, который управляет собственными процессами. Поскольку открытый файл может перебирать свои строки, вы можете передать его объекту pool.map()
, который выполнит цикл и доставит строки в рабочую функцию. Карта блокирует и возвращает весь результат, когда он готов. Имейте в виду, что это слишком упрощенный пример, и что pool.map()
он будет читать весь ваш файл в память сразу перед отправкой работы. Помните об этом, если вы ожидаете иметь большие файлы. Существуют более продвинутые способы создания настройки производителя / потребителя.
Ручной "пул" с пересортировкой лимита и строк
Это ручной пример Pool.map , но вместо того, чтобы использовать всю итерацию за один раз, вы можете установить размер очереди, чтобы вы загружали ее по частям так быстро, как она может обрабатывать. Я также добавил номера строк, чтобы вы могли отслеживать их и ссылаться на них, если хотите, позже.
from multiprocessing import Process, Manager
import time
import itertools
def do_work(in_queue, out_list):
while True:
item = in_queue.get()
line_no, line = item
if line == None:
return
time.sleep(.5)
result = (line_no, line)
out_list.append(result)
if __name__ == "__main__":
num_workers = 4
manager = Manager()
results = manager.list()
work = manager.Queue(num_workers)
pool = []
for i in xrange(num_workers):
p = Process(target=do_work, args=(work, results))
p.start()
pool.append(p)
with open("source.txt") as f:
iters = itertools.chain(f, (None,)*num_workers)
for num_and_line in enumerate(iters):
work.put(num_and_line)
for p in pool:
p.join()
print sorted(results)