Saya tidak akan menyebut concurrent.futures
lebih "maju" - ini adalah antarmuka yang lebih sederhana yang bekerja sangat mirip terlepas dari apakah Anda menggunakan beberapa utas atau beberapa proses sebagai gimmick paralelisasi yang mendasarinya.
Jadi, seperti hampir semua contoh "antarmuka yang lebih sederhana", banyak trade-off yang sama terlibat: ia memiliki kurva belajar yang lebih dangkal, sebagian besar hanya karena ada begitu banyak yang tersedia untuk dipelajari; tetapi, karena ia menawarkan lebih sedikit opsi, pada akhirnya ia mungkin membuat Anda frustrasi dengan cara yang tidak dimiliki oleh antarmuka yang lebih kaya.
Sejauh tugas-tugas yang terikat CPU, itu terlalu kurang ditentukan untuk dikatakan lebih bermakna. Untuk tugas-tugas yang terikat CPU di bawah CPython, Anda membutuhkan beberapa proses daripada beberapa utas untuk memiliki peluang mendapatkan speedup. Tetapi seberapa banyak (jika ada) dari speedup yang Anda dapatkan tergantung pada detail perangkat keras Anda, OS Anda, dan terutama pada seberapa banyak komunikasi antar-proses yang dibutuhkan tugas spesifik Anda. Di bawah penutup, semua gimmicks paralelisasi antar proses bergantung pada primitif OS yang sama - API tingkat tinggi yang Anda gunakan untuk mendapatkannya bukanlah faktor utama dalam kecepatan bottom-line.
Edit: contoh
Berikut ini kode terakhir yang ditampilkan di artikel yang Anda referensikan, tetapi saya menambahkan pernyataan impor yang diperlukan untuk membuatnya berfungsi:
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))}
Inilah hal yang persis sama menggunakan multiprocessing
sebagai gantinya:
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))}
Perhatikan bahwa kemampuan untuk menggunakan multiprocessing.Pool
objek sebagai manajer konteks ditambahkan dalam Python 3.3.
Yang mana yang lebih mudah untuk dikerjakan? LOL ;-) Mereka pada dasarnya identik.
Salah satu perbedaan adalah bahwa Pool
dukungan begitu banyak cara yang berbeda dalam melakukan hal-hal yang Anda mungkin tidak menyadari betapa mudahnya dapat menjadi sampai Anda sudah naik cukup jalan sampai kurva belajar.
Sekali lagi, semua cara yang berbeda itu merupakan kekuatan sekaligus kelemahan. Mereka adalah kekuatan karena fleksibilitas mungkin diperlukan dalam beberapa situasi. Mereka adalah kelemahan karena "lebih disukai hanya satu cara yang jelas untuk melakukannya". Sebuah proyek yang bertahan secara eksklusif (jika mungkin) concurrent.futures
mungkin akan lebih mudah untuk dipertahankan dalam jangka panjang, karena kurangnya kebaruan yang tidak disengaja dalam bagaimana API minimalnya dapat digunakan.
ProcessPoolExecutor
sebenarnya memiliki lebih banyak pilihan daripadaPool
karenaProcessPoolExecutor.submit
pengembalianFuture
kasus yang memungkinkan pembatalan (cancel
), memeriksa yang terkecuali dibesarkan (exception
), dan dinamis menambahkan callback yang akan dipanggil setelah selesai (add_done_callback
). Tidak satu pun dari fitur ini tersedia denganAsyncResult
instance yang dikembalikan olehPool.apply_async
. Dalam cara lainPool
memiliki lebih banyak pilihan karenainitializer
/initargs
,maxtasksperchild
dancontext
diPool.__init__
, dan metode yang lebih terpapar olehPool
contoh.Pool
, itu tentang modul.Pool
adalah bagian kecil dari apa yang ada dimultiprocessing
dalamnya, dan begitu jauh di dalam dokumen, butuh beberapa saat bagi orang untuk menyadari keberadaannyamultiprocessing
. Jawaban khusus ini difokuskanPool
karena hanya itulah artikel yang ditautkan oleh OP, dan itucf
"jauh lebih mudah untuk dikerjakan" sama sekali tidak benar tentang apa yang artikel tersebut bahas. Di luar itu,cf
'sas_completed()
juga bisa sangat berguna.