Python Threading: Sebuah Pengantar
Diterbitkan: 2022-10-25Dalam tutorial ini, Anda akan belajar cara menggunakan modul threading bawaan Python untuk menjelajahi kemampuan multithreading di Python.
Dimulai dengan dasar-dasar proses dan utas, Anda akan mempelajari cara kerja multithreading dengan Python—sambil memahami konsep konkurensi dan paralelisme. Anda kemudian akan mempelajari cara memulai dan menjalankan satu atau lebih utas dengan Python menggunakan modul threading
.
Mari kita mulai.
Proses vs. Utas: Apa Perbedaannya?
Apa Itu Proses?
Proses adalah setiap instance dari program yang perlu dijalankan.
Itu bisa apa saja – skrip Python atau browser web seperti Chrome hingga aplikasi konferensi video. Jika Anda meluncurkan Task Manager pada mesin Anda dan menavigasi ke Performance -> CPU , Anda akan dapat melihat proses dan thread yang sedang berjalan pada core CPU Anda.

Memahami Proses dan Utas
Secara internal, suatu proses memiliki memori khusus yang menyimpan kode dan data yang terkait dengan proses tersebut.
Sebuah proses terdiri dari satu atau lebih thread . Thread adalah urutan instruksi terkecil yang dapat dijalankan oleh sistem operasi, dan mewakili aliran eksekusi.
Setiap utas memiliki tumpukan dan registernya sendiri tetapi bukan memori khusus. Semua utas yang terkait dengan suatu proses dapat mengakses data. Oleh karena itu, data dan memori dibagi oleh semua utas proses.

Dalam CPU dengan N core, N proses dapat dieksekusi secara paralel pada waktu yang sama. Namun, dua utas dari proses yang sama tidak pernah dapat dieksekusi secara paralel - tetapi dapat dieksekusi secara bersamaan. Kami akan membahas konsep konkurensi vs paralelisme di bagian berikutnya.
Berdasarkan apa yang telah kita pelajari sejauh ini, mari kita rangkum perbedaan antara proses dan utas.
Fitur | Proses | Benang |
Penyimpanan | Memori khusus | Berbagi memori |
Modus eksekusi | Paralel, bersamaan | Bersamaan; tapi tidak paralel |
Eksekusi ditangani oleh | Sistem operasi | CPython Interpreter |
Multithreading dengan Python
Dengan Python, Global Interpreter Lock (GIL) memastikan bahwa hanya satu utas yang dapat memperoleh kunci dan dijalankan kapan saja. Semua utas harus mendapatkan kunci ini untuk dijalankan. Ini memastikan bahwa hanya satu utas yang dapat dieksekusi—pada titik waktu tertentu—dan menghindari multithreading secara bersamaan .
Misalnya, pertimbangkan dua utas, t1
dan t2
, dari proses yang sama. Karena utas berbagi data yang sama ketika t1
membaca nilai tertentu k
, t2
dapat memodifikasi nilai k
yang sama . Hal ini dapat menyebabkan kebuntuan dan hasil yang tidak diinginkan. Tetapi hanya satu utas yang dapat memperoleh kunci dan dijalankan kapan saja. Oleh karena itu, GIL juga memastikan keamanan utas .
Jadi bagaimana kita mencapai kemampuan multithreading dengan Python? Untuk memahami ini, mari kita bahas konsep konkurensi dan paralelisme.
Konkurensi vs. Paralelisme: Sebuah Tinjauan
Pertimbangkan CPU dengan lebih dari satu inti. Pada ilustrasi di bawah, CPU memiliki empat inti. Ini berarti bahwa kita dapat menjalankan empat operasi berbeda secara paralel pada saat tertentu.
Jika terdapat empat proses, maka masing-masing proses dapat berjalan secara independen dan simultan pada masing-masing dari keempat core tersebut. Mari kita asumsikan bahwa setiap proses memiliki dua utas.

Untuk memahami cara kerja threading, mari kita beralih dari arsitektur prosesor multicore ke single-core. Seperti yang disebutkan, hanya satu utas yang dapat aktif pada contoh eksekusi tertentu; tetapi inti prosesor dapat beralih di antara utas.

Misalnya, utas terikat I/O sering menunggu operasi I/O: membaca input pengguna, membaca database, dan operasi file. Selama waktu tunggu ini, ia dapat melepaskan kunci sehingga utas lainnya dapat berjalan. Waktu tunggu juga dapat berupa operasi sederhana seperti tidur selama n
detik.
Singkatnya: Selama operasi menunggu, utas melepaskan kunci, memungkinkan inti prosesor untuk beralih ke utas lain. Utas sebelumnya melanjutkan eksekusi setelah masa tunggu selesai. Proses ini, di mana inti prosesor beralih di antara utas secara bersamaan, memfasilitasi multithreading.
Jika Anda ingin menerapkan paralelisme tingkat proses dalam aplikasi Anda, pertimbangkan untuk menggunakan multiprosesor.
Modul Threading Python: Langkah Pertama
Python dikirimkan dengan modul threading
yang dapat Anda impor ke dalam skrip Python.
import threading
Untuk membuat objek utas dengan Python, Anda dapat menggunakan konstruktor Thread
: threading.Thread(...)
. Ini adalah sintaks generik yang cukup untuk sebagian besar implementasi threading:
threading.Thread(target=...,args=...)
Di Sini,
-
target
adalah argumen kata kunci yang menunjukkan panggilan Python -
args
adalah tupel argumen yang diterima target.
Anda memerlukan Python 3.x untuk menjalankan contoh kode dalam tutorial ini. Unduh kodenya dan ikuti.
Cara Mendefinisikan dan Menjalankan Utas dengan Python
Mari kita definisikan utas yang menjalankan fungsi target.
Fungsi target adalah some_func
.
import threading import time def some_func(): print("Running some_func...") time.sleep(2) print("Finished running some_func.") thread1 = threading.Thread(target=some_func) thread1.start() print(threading.active_count())
Mari kita urai apa yang dilakukan cuplikan kode di atas:
- Ini mengimpor modul
threading
dantime
. - Fungsi
some_func
memiliki pernyataan deskriptifprint()
dan menyertakan operasi tidur selama dua detik:time.sleep(n)
menyebabkan fungsi tidur selaman
detik. - Selanjutnya, kita mendefinisikan thread
thread_1
dengan target sebagaisome_func
.threading.Thread(target=...)
membuat objek thread. - Catatan : Tentukan nama fungsi dan bukan pemanggilan fungsi; gunakan
some_func
dan bukansome_func()
. - Membuat objek utas tidak memulai utas; memanggil metode
start()
pada objek utas tidak. - Untuk mendapatkan jumlah utas aktif, kami menggunakan fungsi
active_count()
.
Skrip Python berjalan di utas utama, dan kami membuat utas lain ( thread1
) untuk menjalankan fungsi some_func
sehingga jumlah utas aktif adalah dua, seperti yang terlihat pada output:

# Output Running some_func... 2 Finished running some_func.
Jika kita melihat lebih dekat pada output, kita melihat bahwa saat memulai thread1
, pernyataan print pertama berjalan. Namun selama operasi tidur, prosesor beralih ke utas utama dan mencetak jumlah utas yang aktif—tanpa menunggu thread1
selesai dieksekusi.

Menunggu Utas Selesai Eksekusi
Jika Anda ingin thread1
menyelesaikan eksekusi, Anda dapat memanggil metode join()
di atasnya setelah memulai thread. Melakukannya akan menunggu thread1
menyelesaikan eksekusi tanpa beralih ke utas utama.
import threading import time def some_func(): print("Running some_func...") time.sleep(2) print("Finished running some_func.") thread1 = threading.Thread(target=some_func) thread1.start() thread1.join() print(threading.active_count())
Sekarang, thread1
telah selesai dieksekusi sebelum kita mencetak jumlah thread yang aktif. Jadi hanya utas utama yang berjalan, yang berarti jumlah utas aktif adalah satu.
# Output Running some_func... Finished running some_func. 1
Cara Menjalankan Banyak Utas dengan Python
Selanjutnya, mari kita buat dua utas untuk menjalankan dua fungsi yang berbeda.
Di sini, count_down
adalah fungsi yang mengambil angka sebagai argumen dan menghitung mundur dari angka itu ke nol.
def count_down(n): for i in range(n,-1,-1): print(i)
Kami mendefinisikan count_up
, fungsi Python lain yang menghitung dari nol hingga angka tertentu.
def count_up(n): for i in range(n+1): print(i)
Saat menggunakan fungsi
range()
dengan sintaksrange(start, stop, step)
, titik akhirstop
dikecualikan secara default.– Untuk menghitung mundur dari angka tertentu ke nol, Anda dapat menggunakan nilai
step
negatif -1 dan mengatur nilaistop
ke -1 sehingga nol disertakan.– Demikian pula, untuk menghitung hingga
n
, Anda harus mengatur nilaistop
ken + 1
. Karena nilai defaultstart
danstep
masing-masing adalah 0 dan 1, Anda dapat menggunakanrange(n + 1)
untuk mendapatkan urutan 0 hingga n.
Selanjutnya, kita mendefinisikan dua utas, thread1
dan thread2
untuk menjalankan fungsi count_down
dan count_up
, masing-masing. Kami menambahkan pernyataan print
dan operasi sleep
untuk kedua fungsi tersebut.
Saat membuat objek utas, perhatikan bahwa argumen ke fungsi target harus ditetapkan sebagai tupel—untuk parameter args
. Karena kedua fungsi ( count_down
dan count_up
) mengambil satu argumen. Anda harus memasukkan koma secara eksplisit setelah nilainya. Ini memastikan argumen masih diteruskan sebagai Tuple, karena elemen berikutnya disimpulkan sebagai None
.
import threading import time def count_down(n): for i in range(n,-1,-1): print("Running thread1....") print(i) time.sleep(1) def count_up(n): for i in range(n+1): print("Running thread2...") print(i) time.sleep(1) thread1 = threading.Thread(target=count_down,args=(10,)) thread2 = threading.Thread(target=count_up,args=(5,)) thread1.start() thread2.start()
Dalam keluaran:
- Fungsi
count_up
berjalan padathread2
dan menghitung hingga 5 mulai dari 0. - Fungsi
count_down
berjalan padathread1
menghitung mundur dari 10 ke 0.
# Output Running thread1.... 10 Running thread2... 0 Running thread1.... 9 Running thread2... 1 Running thread1.... 8 Running thread2... 2 Running thread1.... 7 Running thread2... 3 Running thread1.... 6 Running thread2... 4 Running thread1.... 5 Running thread2... 5 Running thread1.... 4 Running thread1.... 3 Running thread1.... 2 Running thread1.... 1 Running thread1.... 0
Anda dapat melihat bahwa thread1
dan thread2
dijalankan secara alternatif, karena keduanya melibatkan operasi menunggu (tidur). Setelah fungsi count_up
selesai menghitung hingga 5, thread2
tidak lagi aktif. Jadi kami mendapatkan output yang sesuai dengan hanya thread1
.
Menyimpulkan
Dalam tutorial ini, Anda telah belajar cara menggunakan modul threading bawaan Python untuk mengimplementasikan multithreading. Berikut ringkasan dari takeaways utama:
- Konstruktor Thread dapat digunakan untuk membuat objek thread. Menggunakan threading.Thread(target=<callable>,args=(<tuple of args>)) membuat utas yang menjalankan target yang dapat dipanggil dengan argumen yang ditentukan dalam args .
- Program Python berjalan pada utas utama, sehingga objek utas yang Anda buat adalah utas tambahan. Anda dapat memanggil fungsi active_count() mengembalikan jumlah utas aktif kapan saja.
- Anda dapat memulai thread menggunakan metode start() pada objek thread dan menunggu hingga eksekusi selesai menggunakan metode join() .
Anda dapat membuat kode contoh tambahan dengan mengubah waktu tunggu, mencoba operasi I/O yang berbeda, dan banyak lagi. Pastikan untuk mengimplementasikan multithreading dalam proyek Python Anda yang akan datang. Selamat mengkode!