Pomyślałem, że uproszczę najprostsze przykłady skopiowane z góry, pracując dla mnie na Py3.6. Najprostszy to multiprocessing.Pool
:
import multiprocessing
import time
def worker(x):
time.sleep(1)
return x
pool = multiprocessing.Pool()
print(pool.map(worker, range(10)))
Możesz ustawić liczbę procesów w puli, używając np Pool(processes=5)
. Domyślnie jest to jednak liczba procesorów, więc pozostaw puste dla zadań związanych z procesorem. (Zadania związane z operacjami we / wy często i tak odpowiadają wątkom, ponieważ wątki w większości czekają, więc mogą współużytkować rdzeń procesora). Pool
Stosuje również optymalizację porcji .
(Należy zauważyć, że metody roboczej nie można zagnieździć w metodzie. Początkowo zdefiniowałem metodę roboczą w metodzie, która wywołuje wywołanie pool.map
, aby zachować ją jako całość, ale potem procesy nie mogły jej zaimportować, i zgłosiło błąd „AttributeError” : Nie można marynować lokalnego obiektu outer_method..inner_method ". Więcej tutaj . Może być wewnątrz klasy.)
(Doceń 'represent!'
raczej oryginalne pytanie zadane podczas drukowania time.sleep()
, ale bez niego pomyślałem, że jakiś kod działałby równolegle, gdy nie był).
Py3 ProcessPoolExecutor
ma również dwie linie ( .map
zwraca generator, więc potrzebujesz list()
):
from concurrent.futures import ProcessPoolExecutor
with ProcessPoolExecutor() as executor:
print(list(executor.map(worker, range(10))))
Z prostymi Process
es:
import multiprocessing
import time
def worker(x, queue):
time.sleep(1)
queue.put(x)
queue = multiprocessing.SimpleQueue()
tasks = range(10)
for task in tasks:
multiprocessing.Process(target=worker, args=(task, queue,)).start()
for _ in tasks:
print(queue.get())
Użyj, SimpleQueue
jeśli wszystko czego potrzebujesz to put
i get
. Pierwsza pętla rozpoczyna wszystkie procesy, zanim druga wykona queue.get
wywołania blokujące . Nie wydaje mi się, żeby dzwonić p.join()
.
multiprocessing.Queue
, a nieManager
tutaj. Użycie aManager
wymaga odrodzenia całkowicie nowego procesu, który jest przesadą, kiedyQueue
to zrobi.