Ви шукаєте шаблон виробника / споживача
Приклад базової різьби
Ось базовий приклад використання потокового модуля (замість багатопроцесорної обробки)
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()
Ви не поділилися б об'єктом файлу з потоками. Ви могли б зробити для них роботу, надавши черзі рядки даних. Потім кожен потік підбирав рядок, обробляв його, а потім повертав у чергу.
У мультипроцесорний модуль вбудовано кілька вдосконалених засобів для обміну даними, таких як списки та особливий вид черги . Існують компроміси щодо використання багатопроцесорної обробки проти потоків, і це залежить від того, чи ваша робота пов’язана з процесором чи IO.
Базова багатопроцесорна робота. Приклад басейну
Ось справді базовий приклад багатопроцесорного пулу
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)