Nie nazwałbym concurrent.futures
bardziej „zaawansowanym” - jest to prostszy interfejs, który działa tak samo, niezależnie od tego, czy używasz wielu wątków, czy wielu procesów jako podstawowej sztuczki równoległej.
Tak więc, podobnie jak praktycznie we wszystkich przypadkach „prostszego interfejsu”, występują takie same kompromisy: ma płytszą krzywą uczenia się, w dużej mierze dlatego, że jest o wiele mniej dostępnych do nauczenia; ale ponieważ oferuje mniej opcji, może ostatecznie frustrować Cię w sposób, w jaki bogatsze interfejsy nie będą.
Jeśli chodzi o zadania związane z procesorem, to jest to zbyt mało zdefiniowane, aby powiedzieć, że ma dużo znaczenia. W przypadku zadań związanych z procesorem w CPythonie, potrzebujesz wielu procesów, a nie wielu wątków, aby mieć szansę na przyspieszenie. Ale to, ile (jeśli w ogóle) uzyskasz przyspieszenia, zależy od szczegółów sprzętu, systemu operacyjnego, a zwłaszcza od tego, ile komunikacji między procesami wymagają określone zadania. Pod okładkami wszystkie sztuczki zrównoleglania między procesami opierają się na tych samych prymitywach systemu operacyjnego - interfejs API wysokiego poziomu, którego używasz, nie jest głównym czynnikiem wpływającym na prędkość końcową.
Edycja: przykład
Oto ostateczny kod pokazany w artykule, do którego się odwołałeś, ale dodaję instrukcję importu potrzebną do jej działania:
from concurrent.futures import ProcessPoolExecutor
def pool_factorizer_map(nums, nprocs):
# Let the executor divide the work among processes by using 'map'.
with ProcessPoolExecutor(max_workers=nprocs) as executor:
return {num:factors for num, factors in
zip(nums,
executor.map(factorize_naive, nums))}
Oto dokładnie to samo, używając multiprocessing
zamiast tego:
import multiprocessing as mp
def mp_factorizer_map(nums, nprocs):
with mp.Pool(nprocs) as pool:
return {num:factors for num, factors in
zip(nums,
pool.map(factorize_naive, nums))}
Zwróć uwagę, że możliwość użycia multiprocessing.Pool
obiektów jako menedżerów kontekstu została dodana w Pythonie 3.3.
Z którym łatwiej się pracuje? LOL ;-) Są zasadniczo identyczne.
Jedna różnica polega na tym, że Pool
obsługuje tak wiele różnych sposobów robienia rzeczy, że możesz nie zdawać sobie sprawy, jak łatwo może to być być, dopóki nie wespniesz się dość daleko po krzywej uczenia się.
Ponownie, wszystkie te różne sposoby są zarówno mocną, jak i słabą stroną. Są mocną stroną, ponieważ w niektórych sytuacjach może być wymagana elastyczność. Są słabością ze względu na „najlepiej tylko jeden oczywisty sposób na zrobienie tego”. Projekt trzymający się wyłącznie (jeśli to możliwe) concurrent.futures
będzie prawdopodobnie łatwiejszy w utrzymaniu w dłuższej perspektywie, ze względu na brak darmowej nowości w sposobie wykorzystania jego minimalnego API.