Modul `concurrent` di Python
Dalam artikel ini, kami akan menjelaskan modul concurrent di Python.
Sambil memperjelas konsep konkruensi dan paralelisme, kami akan menjelaskan cara mengimplementasikan pemrosesan asinkron menggunakan modul concurrent dengan contoh praktis.
YouTube Video
Modul concurrent di Python
Saat mempercepat pemrosesan di Python, penting untuk memperhatikan perbedaan antara konkruensi dan paralelisme. Modul concurrent merupakan cara penting untuk menangani pemrosesan asinkron dengan aman dan sederhana sambil memperhatikan perbedaan ini.
Perbedaan antara Konkruensi dan Paralelisme
-
Konkruensi berarti merancang sebuah proses sehingga beberapa tugas berjalan dengan berpindah di antara mereka dalam unit kerja kecil. Bahkan jika tugas-tugas tidak benar-benar berjalan secara bersamaan, memanfaatkan "waktu tunggu" memungkinkan Anda membuat keseluruhan proses lebih efisien.
-
Paralelisme adalah mekanisme yang secara fisik menjalankan beberapa tugas secara bersamaan. Dengan menggunakan beberapa inti CPU, pemrosesan dapat dilakukan secara bersamaan.
Keduanya adalah teknik untuk mempercepat pemrosesan, tetapi konkruensi adalah masalah desain tentang 'bagaimana melanjutkan', sedangkan paralelisme adalah masalah eksekusi tentang 'bagaimana itu berjalan', sehingga keduanya berbeda secara mendasar.
Apa itu Modul concurrent?
concurrent adalah pustaka standar di Python yang menyediakan API tingkat tinggi untuk menangani konkruensi dan paralelisme secara aman dan sederhana. Ini dirancang agar Anda dapat fokus pada 'menjalankan tugas' tanpa harus khawatir tentang operasi tingkat rendah seperti membuat dan mengelola thread atau proses.
Peran ThreadPoolExecutor dan ProcessPoolExecutor
Modul concurrent menyediakan dua opsi utama tergantung pada sifat tugasnya.
-
ThreadPoolExecutorIni cocok untuk implementasi konkruen, terutama untuk tugas dengan banyak waktu tunggu I/O, seperti operasi jaringan atau file. Dengan beralih di antara tugas, modul ini memanfaatkan waktu tunggu secara efektif. -
ProcessPoolExecutorImplementasi ini ditujukan untuk pemrosesan paralel dan cocok untuk tugas yang intensif CPU. Ini menggunakan beberapa proses untuk memaksimalkan penggunaan inti CPU yang tersedia secara paralel.
Dengan demikian, fitur utama dari modul concurrent adalah memberikan struktur yang memungkinkan Anda untuk memilih secara tepat antara konkruensi dan paralelisme sesuai kebutuhan.
Dasar-dasar ThreadPoolExecutor (Untuk Tugas I/O)
ThreadPoolExecutor cocok untuk tugas yang bergantung pada I/O, seperti komunikasi jaringan dan operasi file. Modul ini membagikan tugas di antara beberapa thread, sehingga waktu tunggu dapat dimanfaatkan secara efektif.
1from concurrent.futures import ThreadPoolExecutor
2import time
3
4def fetch_data(n):
5 # Simulate an I/O-bound task
6 time.sleep(1)
7 return f"data-{n}"
8
9with ThreadPoolExecutor(max_workers=3) as executor:
10 futures = [executor.submit(fetch_data, i) for i in range(5)]
11
12 for future in futures:
13 print(future.result())- Pada contoh ini, beberapa tugas I/O yang menunggu satu detik dieksekusi secara konkruen. Dengan menggunakan
submit, pemanggilan fungsi didaftarkan sebagai tugas asinkron, dan dengan memanggilresult(), Anda bisa menunggu sampai selesai dan mendapatkan hasilnya, memungkinkan Anda mengimplementasikan pemrosesan konkruen yang memanfaatkan waktu tunggu dengan cara yang ringkas.
Konkruensi Sederhana Menggunakan map
Jika kontrol yang kompleks tidak diperlukan, menggunakan map dapat membuat kode Anda lebih ringkas.
1from concurrent.futures import ThreadPoolExecutor
2import time
3
4def fetch_data(n):
5 # Simulate an I/O-bound task
6 time.sleep(1)
7 return f"data-{n}"
8
9with ThreadPoolExecutor(max_workers=3) as executor:
10 results = executor.map(fetch_data, range(5))
11
12 for result in results:
13 print(result)- Dalam contoh ini, beberapa tugas I/O dieksekusi secara konkruen menggunakan
ThreadPoolExecutor.map. Karenamapmengembalikan hasil dalam urutan yang sama dengan inputnya, Anda dapat menulis kode yang hampir menyerupai pemrosesan berurutan, dan eksekusi secara konkruen bisa dilakukan tanpa sadar akan pemrosesan asinkron—ini adalah keunggulan utama.
Dasar-dasar ProcessPoolExecutor (Untuk Tugas yang Membutuhkan CPU)
Untuk komputasi berat yang benar-benar menggunakan CPU secara maksimal, Anda sebaiknya menggunakan proses daripada thread. Hal ini memungkinkan Anda menghindari keterbatasan Global Interpreter Lock (GIL).
1from concurrent.futures import ProcessPoolExecutor
2
3def heavy_calculation(n):
4 # Simulate a CPU-bound task
5 total = 0
6 for i in range(10_000_000):
7 total += i * n
8 return total
9
10if __name__ == "__main__":
11 with ProcessPoolExecutor(max_workers=4) as executor:
12 results = executor.map(heavy_calculation, range(4))
13
14 for result in results:
15 print(result)Pada contoh ini, komputasi yang membutuhkan CPU besar dieksekusi secara paralel menggunakan ProcessPoolExecutor. Karena pembuatan proses terlibat, diperlukan pelindung __main__, yang memungkinkan pemrosesan paralel yang aman menggunakan beberapa inti CPU.
Pemrosesan Berdasarkan Urutan Selesai Menggunakan as_completed
as_completed berguna saat Anda ingin menangani hasil sesuai urutan penyelesaiannya.
1from concurrent.futures import ThreadPoolExecutor, as_completed
2import time
3
4def fetch_data(n):
5 # Simulate an I/O-bound task
6 time.sleep(1)
7 return f"data-{n}"
8
9with ThreadPoolExecutor(max_workers=3) as executor:
10 futures = [executor.submit(fetch_data, i) for i in range(5)]
11
12 for future in as_completed(futures):
13 print(future.result())- Pada contoh ini, beberapa tugas asinkron dieksekusi secara bersamaan, dan hasilnya diambil sesuai urutan penyelesaiannya. Dengan menggunakan
as_completed, Anda dapat menangani hasil dengan cepat tanpa memperhatikan urutan tugas, sehingga cocok untuk menampilkan progres atau situasi yang memerlukan penanganan berurutan.
Penanganan Eksepsi
Dalam concurrent, eksepsi akan muncul saat Anda memanggil result().
1from concurrent.futures import ThreadPoolExecutor
2
3def risky_task(n):
4 # Simulate a task that may fail for a specific input
5 if n == 3:
6 raise ValueError("Something went wrong")
7 return n * 2
8
9with ThreadPoolExecutor() as executor:
10 futures = [executor.submit(risky_task, i) for i in range(5)]
11
12 for future in futures:
13 try:
14 print(future.result())
15 except Exception as e:
16 print("Error:", e)- Contoh ini menunjukkan bahwa meskipun beberapa tugas menghasilkan eksepsi, tugas lainnya tetap berjalan dan Anda dapat menangani eksepsi secara terpisah saat mengambil hasil. Dengan menggunakan
Futuredariconcurrent, penting untuk bisa menangani keberhasilan dan kegagalan pemrosesan asinkron dengan aman.
Panduan Memilih antara Thread dan Proses
Untuk menggunakan konkruensi dan paralelisme secara efektif, penting untuk memilih pendekatan yang tepat berdasarkan sifat tugas.
Dalam praktiknya, kriteria berikut dapat membantu Anda memutuskan.
- Untuk proses dengan banyak waktu tunggu I/O, seperti komunikasi atau operasi file, gunakan
ThreadPoolExecutor. - Untuk tugas berat yang membutuhkan banyak CPU, gunakan
ProcessPoolExecutor. - Jika ada banyak tugas sederhana, penggunaan
mapmemungkinkan Anda menulis kode yang lebih ringkas. - Jika kontrol urutan eksekusi atau penanganan eksepsi sangat penting, kombinasikan
submitdenganas_completed.
Manfaat Menggunakan concurrent
Dengan menggunakan modul concurrent, Anda dapat menangani pemrosesan asinkron dengan aman dan intuitif.
Manfaat utamanya adalah sebagai berikut:.
- Anda tidak perlu repot mengelola thread atau proses tingkat rendah.
- Modul ini disediakan sebagai bagian dari pustaka standar Python, sehingga Anda dapat menggunakannya dengan percaya diri.
- Kode menjadi lebih mudah dibaca dan dipelihara.
- Ini sangat ideal sebagai langkah awal untuk mempelajari konkruensi dan paralelisme.
Cukup dengan mengingat panduan ini, Anda dapat sangat mengurangi kegagalan dalam implementasi yang menggunakan concurrent.
Ringkasan
Modul concurrent adalah pilihan standar untuk konkruensi dan paralelisme praktis di Python. Itu memungkinkan Anda meningkatkan performa tanpa banyak mengubah isi pemrosesan Anda, yang merupakan keuntungan signifikan dalam praktik. Dengan menggunakan concurrent, Anda dapat mengimplementasikan pemrosesan asinkron secara ringkas sekaligus menangani eksepsi dan kontrol eksekusi dengan aman.
Anda dapat mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Silakan periksa juga saluran YouTube kami.