Lewati ke konten utama

Multiprocessing di Python: Panduan Threads dan Proses

Pelajari cara mengelola thread dan proses dengan modul multiprocessing di Python. Temukan teknik kunci untuk pemrograman paralel. Tingkatkan efisiensi kode Anda dengan contoh.
· 7 mnt Baca

Jelajahi bersama AI

Pustaka standar Python dilengkapi dengan beberapa paket bawaan agar pengembang dapat langsung memetik manfaat dari bahasa ini.

Salah satu paket tersebut adalah modul multiprocessing yang memungkinkan sistem menjalankan banyak proses secara bersamaan. Dengan kata lain, pengembang dapat memecah aplikasi menjadi thread yang lebih kecil dan berjalan mandiri dari kode Python mereka. Thread atau proses ini kemudian dialokasikan ke prosesor oleh sistem operasi, memungkinkan mereka berjalan paralel, sehingga meningkatkan kinerja dan efisiensi program Python Anda. 

Jika istilah seperti thread, proses, prosesor, dan sebagainya masih asing bagi Anda, jangan khawatir. Di artikel ini, kami akan membahas definisi proses, perbedaannya dengan thread, dan cara menggunakan modul multiprocessing. 

Apa itu Proses di Python?

Memahami konsep proses dan thread sangat berguna untuk memahami lebih baik bagaimana sistem operasi mengelola program melalui berbagai tahap eksekusi. Proses hanyalah acuan ke sebuah program komputer. Setiap program memiliki satu proses yang terkait dengannya. 

Saat Anda membaca artikel ini, besar kemungkinan komputer Anda menjalankan banyak proses pada saat yang sama, meskipun hanya ada beberapa program yang terbuka – ini karena sebagian besar sistem operasi memiliki banyak tugas yang berjalan di latar belakang. Misalnya, Anda mungkin hanya menjalankan tiga program saat ini, tetapi komputer Anda bisa saja memiliki lebih dari 30 proses aktif yang berjalan secara bersamaan. 

Cara memeriksa proses aktif yang sedang berjalan di komputer Anda bergantung pada sistem operasi: 

  • Di Windows: Ctrl+Shift+Esc akan membuka Task Manager 
  • Di Mac: buka Spotlight Search di Mac dan ketik "Activity Monitor", lalu tekan Return  
  • Di Linux: klik Application Menu dan cari System Monitor. 

Python menyediakan akses ke proses tingkat sistem yang sesungguhnya. Membuat instance dari kelas Process dari modul multiprocessing memungkinkan pengembang mereferensikan proses native yang mendasarinya menggunakan Python. Sebuah proses native baru dibuat di balik layar ketika sebuah proses dimulai. Siklus hidup proses Python terdiri dari tiga tahap: inisiasi proses baru, proses berjalan, dan proses diakhiri – kita akan membahas masing-masing tahap.

Semua proses tersusun dari satu atau lebih thread. Masih ingat saat kita menyebutkan bahwa “proses hanyalah acuan ke sebuah program komputer?” Nah, setiap program Python adalah proses yang terdiri dari satu thread bawaan yang disebut main thread. Main thread bertanggung jawab untuk mengeksekusi instruksi dalam program Python Anda. Namun, penting untuk dicatat bahwa proses dan thread itu berbeda. 

Multiprocessing vs. Threading

Lebih spesifiknya, satu instance interpreter Python – alat yang mengonversi kode Python menjadi bahasa yang dipahami komputer – setara dengan satu proses. Sebuah proses akan terdiri dari setidaknya satu thread, yang disebut “main thread” di Python, meskipun thread lain dapat dibuat dalam proses yang sama – semua thread lain yang dibuat dalam sebuah proses akan menjadi milik proses tersebut. 

Thread berfungsi sebagai representasi bagaimana program Python Anda akan dieksekusi, dan setelah semua thread non-latar belakang diakhiri, proses Python akan berhenti. 

  • Proses: Satu proses adalah instance interpreter Python yang terdiri dari setidaknya satu thread bernama main thread. 
  • Thread: Representasi cara sebuah program Python dieksekusi dalam sebuah proses Python.

Python memiliki dua kelas yang sangat mirip yang memberi kita kontrol lebih atas proses dan thread: multiprocessing.Process dan threading.Thread.

Mari tinjau beberapa persamaan dan perbedaannya. 

Persamaan

Konkurensi

Konkurensi adalah konsep di mana bagian-bagian berbeda dari program dapat dieksekusi tidak berurutan atau sebagian berurutan tanpa memengaruhi hasil akhir. Kedua kelas awalnya ditujukan untuk konkurensi. 

Dukungan untuk primitive konkurensi

Kelas multiprocessing.Process dan threading.Thread mendukung primitive konkurensi yang sama – alat yang memungkinkan sinkronisasi dan koordinasi thread dan proses. 

API seragam

Setelah Anda memahami API multiprocessing.Process, Anda dapat mentransfer pengetahuan itu ke API threading.Thread, dan sebaliknya. Memang sengaja dirancang demikian. 

Perbedaan

Fungsionalitas

Meski API-nya sama, proses dan thread itu berbeda. Proses adalah tingkat abstraksi yang lebih tinggi daripada thread: proses adalah acuan ke program komputer, dan thread berada di dalam sebuah proses. Perbedaan ini melekat pada kelas-kelasnya. Karenanya, kelas-kelas tersebut merepresentasikan dua fungsi native berbeda yang dikelola oleh sistem operasi yang mendasarinya. 

Akses ke state bersama

Kedua kelas mengakses state bersama dengan cara berbeda. Karena thread berada dalam sebuah proses, mereka dapat berbagi memori di dalam proses. Jadi, sebuah fungsi yang dieksekusi dalam thread baru masih memiliki akses ke data dan state yang sama dalam proses. Cara thread berbagi state satu sama lain dikenal sebagai “shared memory” dan cukup lugas. Sebaliknya, berbagi state antarproses jauh lebih rumit: state harus diserialisasi dan dikirimkan antarproses. Dengan kata lain, proses tidak menggunakan shared memory untuk berbagi state karena masing-masing memiliki memori terpisah. Sebagai gantinya, proses berbagi data menggunakan teknik yang disebut “inter-process communication,” dan untuk melakukannya di Python memerlukan alat eksplisit lain seperti multiprocessing.Pipe atau multiprocessing.Queue. 

GIL

Global Interpreter Lock (GIL) Python adalah kunci yang hanya mengizinkan satu thread menguasai interpreter Python pada satu waktu. Banyak thread tunduk pada GIL, yang sering membuat penggunaan multithreading di Python menjadi ide yang kurang baik: eksekusi multi-core sejati melalui multithreading tidak didukung oleh Python pada interpreter CPython. Namun, proses tidak tunduk pada GIL karena GIL digunakan di dalam setiap proses Python, bukan lintas proses. 

Dari sisi kasus penggunaan, multiprocessing sering lebih unggul dari threading pada skenario program yang intensif CPU dan tidak perlu melakukan IO atau interaksi pengguna. Threading lebih cocok untuk program yang terikat IO atau jaringan dan pada skenario ketika tujuannya membuat aplikasi lebih responsif. 

Manfaat Multiprocessing di Python

Bayangkan prosesor sebagai seorang wirausahawan. Seiring bisnis sang wirausahawan berkembang, semakin banyak tugas yang harus dikelola agar tetap sejalan dengan pertumbuhan bisnis. Jika wirausahawan memutuskan untuk menangani semua tugas itu sendirian (mis., akuntansi, penjualan, pemasaran, inovasi, dan lain-lain), ia berisiko menurunkan efisiensi dan kinerja bisnis secara keseluruhan karena satu orang hanya bisa melakukan begitu banyak hal pada satu waktu. Misalnya, sebelum beralih ke tugas inovasi, ia harus menghentikan tugas penjualan – ini dikenal sebagai menjalankan tugas secara “sekuensial.” 

Kebanyakan wirausahawan paham bahwa mencoba melakukan semuanya sendiri adalah ide buruk. Akibatnya, mereka biasanya mengimbangi pertumbuhan jumlah tugas dengan mempekerjakan karyawan untuk mengelola berbagai departemen. Dengan cara ini, tugas dapat dilakukan secara paralel – artinya satu tugas tidak perlu dihentikan agar tugas lain berjalan. Mempekerjakan lebih banyak karyawan untuk melakukan tugas tertentu mirip dengan menggunakan banyak prosesor untuk menjalankan operasi. Misalnya, proyek computer vision cukup menuntut karena Anda biasanya harus memproses banyak data gambar yang memakan waktu: untuk mempercepat prosedur ini, Anda bisa memproses banyak gambar secara paralel. 

Jadi, kita dapat mengatakan bahwa multiprocessing berguna untuk membuat program lebih efisien dengan membagi dan menugaskan tugas ke prosesor yang berbeda. Modul multiprocessing Python menyederhanakan ini lebih jauh dengan berfungsi sebagai alat tingkat tinggi untuk meningkatkan efisiensi program Anda dengan menugaskan tugas ke berbagai proses. 

Dasar-dasar Modul Multiprocessing di Python 

Kita telah menyebutkan bahwa siklus hidup proses Python terdiri dari tiga tahap: proses baru, proses berjalan, dan proses diakhiri. Bagian ini akan membahas lebih dalam setiap fase siklus hidup dan menyediakan contoh kode. Anda dapat mengakses kodenya untuk diikuti melalui DataLab workbook kami. 

Proses baru 

Proses baru dapat didefinisikan sebagai proses yang dibuat dengan menginstansiasi kelas Process. Proses anak akan dibuat ketika kita menugaskan objek Process ke sebuah variabel. 

from multiprocessing import Process

# Create a new process
process = Process()

Saat ini, instance proses kita belum melakukan apa pun karena kita menginisialisasi objek Process kosong. Kita bisa mengubah konfigurasi objek Process kita untuk mengeksekusi fungsi tertentu dengan meneruskan fungsi yang ingin kita jalankan di proses berbeda ke parameter target kelas. 

# Create a new process with a specified function to execute.
def example_function():
    pass

new_process = Process(target=example_function)

Jika fungsi target kita juga memiliki parameter, maka kita cukup meneruskannya ke parameter args dari objek Process sebagai tuple.

Tip: Pelajari cara menulis fungsi di Python dengan kursus interaktif Writing Functions in Python. 

# Create a new process with specific function to execute with args.
def example(args):
    pass

process = Process(target=example, args=("Hi",))

Perhatikan bahwa kita baru saja membuat proses baru, tetapi proses tersebut belum berjalan. 

Mari lihat bagaimana kita dapat menjalankan proses baru.  

Proses berjalan 

Menjalankan proses baru cukup mudah: cukup panggil metode start() pada instance proses. 

# Run the new process
process.start()

 Tindakan ini memulai aktivitas proses dengan memanggil metode run() dari instance Process di balik layar. Metode run() juga bertanggung jawab untuk memanggil fungsi kustom yang ditentukan di parameter target instance Process (jika ditentukan).

Ingat kembali bahwa sebelumnya di tutorial ini kita menyatakan setiap proses memiliki setidaknya satu thread bernama main thread – ini adalah default. Jadi, ketika proses anak dimulai, main thread dibuat untuk proses anak tersebut dan dijalankan. Main thread bertanggung jawab mengeksekusi semua kode kita di proses anak. 

Kita dapat memeriksa apakah instance proses kita hidup sejak metode start() mengembalikan nilai hingga proses anak berhenti dengan menggunakan metode is_alive() pada instance Process kita. 

Catatan: Jika Anda menguji ini di notebook, pemanggilan is_alive() harus berada di sel yang sama dengan pemanggilan metode start() agar dapat menangkap proses yang sedang berjalan. 

# Run the new process
process.start()

# Check process is running
process.is_alive()

"""
True
"""

Jika proses tidak berjalan, pemanggilan metode is_alive() akan mengembalikan False. 

Proses diakhiri

Ketika fungsi run() mengembalikan nilai atau keluar, proses diakhiri: kita tidak harus melakukan apa pun secara eksplisit. Dengan kata lain, Anda dapat mengharapkan proses berakhir setelah instruksi yang Anda tetapkan sebagai fungsi target selesai. Dengan demikian, metode is_alive() akan mengembalikan false. 

# Check process is terminated - should return false.
process.is_alive()

"""
False
"""

Namun, sebuah proses juga dapat diakhiri jika menemui pengecualian yang tidak tertangani atau terjadi error. Misalnya, jika ada error pada fungsi yang Anda tetapkan sebagai target, proses akan berakhir. 

# Create a new process with a specific function that has an error
# to execute with args.
def example(args):
    split_args = list(args.split())
    # "name" variable is not in the function namespace - should raise error
    return name

# New process
process = Process(target=example, args=("Hi",))

# Running the new process
process.start()

# Check process is running
process.is_alive()

"""
True

Process Process-15:
Traceback (most recent call last):
  File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
"""

Objek Process juga memiliki metode terminate() dan kill() yang memungkinkan pengguna mengakhiri proses secara paksa. 

# Create a new process with a specific function to execute with args.
def example(args):
    split_args = list(args.split())
    # "name" variable is not in the function namespace - should raise error
    return split_args

# New process
process = Process(target=example, args=("Hi",))

# Running the new process
process.start()

if process.is_alive():
    process.terminate() # You can also use process.kill()
    print("Process terminated forcefully")

"""
Process terminated forcefully
"""

Penting untuk dicatat bahwa penghentian secara paksa bukanlah cara yang direkomendasikan untuk mengakhiri proses: cara ini mungkin tidak menutup semua sumber daya yang terbuka dengan aman atau menyimpan state program yang diperlukan. Solusi yang lebih baik adalah menggunakan penghentian terkontrol dengan flag boolean yang aman untuk proses atau alat serupa. 

Tutorial Multiprocessing Python

Sekarang Anda memahami dasar-dasar multiprocessing, mari kita kerjakan sebuah contoh untuk menunjukkan cara melakukan pemrograman konkuren di Python. 

Fungsi yang kita buat akan sekadar mencetak sebuah pernyataan, tidur selama 1 detik, lalu mencetak pernyataan lainnya – pelajari lebih lanjut tentang fungsi di tutorial fungsi Python ini. 

import time

def do_something():
    print("I'm going to sleep")
    time.sleep(1)
    print("I'm awake") 

Langkah pertama adalah membuat proses baru: kita akan membuat dua. 

# Create new child process

process_1 = Process(target=do_something)
process_2 = Process(target=do_something)

Beginilah tampilan program konkuren di lingkungan notebook: 

%%time

# Starts both processes
process_1.start()
process_2.start()

"""
I'm going to sleep
CPU times: user 810 µs, sys: 7.34 ms, total: 8.15 ms
Wall time: 6.04 ms
I'm going to sleep
"""

Melihat output program, cukup jelas ada masalah pada kode kita. Pengukur waktu dicetak di tengah proses pertama, dan pernyataan cetak kedua tidak tercetak. 

Ini terjadi karena ada tiga proses yang berjalan: proses utama, serta process_1 dan process_2. Proses yang melacak waktu dan mencetaknya adalah proses utama. Agar proses utama kita menunggu sebelum mencetak waktu, kita harus memanggil metode join() pada kedua proses tersebut setelah menjalankannya.

Catatan: Jika Anda tertarik belajar lebih lanjut, lihat diskusi Stackoverflow ini. 

Mari lihat cuplikan kode baru kita: 

%%time
​
# Create new child process (Cannot run a process more than once)
new_process_1 = Process(target=do_something)
new_process_2 = Process(target=do_something)
​
# Starts both processes
new_process_1.start()
new_process_2.start()
​
new_process_1.join()
new_process_2.join()

"""
I'm going to sleep
I'm going to sleep
I'm awake
I'm awake
CPU times: user 0 ns, sys: 14 ms, total: 14 ms
Wall time: 1.01 s
"""

Masalah teratasi. 

Wall time pada run ini sedikit lebih lama dari run pertama. Namun, run ini menyelesaikan pemanggilan ke kedua fungsi target sebelum mengembalikan informasi waktu. Kita juga dapat menerapkan logika yang sama untuk membuat lebih banyak proses berjalan secara konkuren. 

Pemikiran Akhir tentang Multiprocessing di Python

Dalam tutorial ini, Anda mempelajari cara membuat program Python lebih efisien dengan menjalankannya secara konkuren. Secara khusus, Anda mempelajari: 

  • Apa itu proses dan bagaimana Anda dapat melihatnya di komputer Anda.
  • Persamaan dan perbedaan antara modul multiprocessing dan threading di Python.
  • Dasar-dasar modul multiprocessing dan cara menjalankan program Python secara konkuren menggunakan multiprocessing. 

Ingin belajar lebih lanjut tentang Pemrograman di Python? Lihat jalur karier Python Programmer kami. Tidak diperlukan pengalaman pemrograman sebelumnya, dan pada akhir jalur ini, Anda akan memiliki keterampilan yang diperlukan untuk mengembangkan perangkat lunak, mengelola data, dan melakukan analisis tingkat lanjut di Python. 

Kurtis Pykes

Penulis

Kurtis Pykes

Topik

Terkait

blogs

Tutorial Korelasi di R

blogs

Spaghetti Plot dan Jalur Badai