Menguasai Komunikasi Antar-Thread dengan Python:Sinkronisasi &Berbagi Data
Komunikasi Antar-Thread mengacu pada proses mengaktifkan komunikasi dan sinkronisasi antar thread dalam program multi-thread Python.
Umumnya, thread di Python berbagi ruang memori yang sama dalam suatu proses, yang memungkinkan mereka untuk bertukar data dan mengoordinasikan aktivitas mereka melalui variabel, objek, dan mekanisme sinkronisasi khusus yang disediakan oleh modul threading.
Untuk memfasilitasi komunikasi antar-thread, modul threading menyediakan berbagai primitif sinkronisasi seperti objek Locks, Events, Conditions, dan Semaphores. Dalam tutorial ini Anda akan mempelajari cara menggunakan objek Event dan Condition untuk menyediakan komunikasi antar thread dalam program multi-thread.
Objek Peristiwa
Objek Peristiwa mengelola status bendera internal sehingga thread dapat menunggu atau disetel. Objek peristiwa menyediakan metode untuk mengontrol status tanda ini, memungkinkan thread menyinkronkan aktivitasnya berdasarkan kondisi bersama.
Bendera awalnya salah dan menjadi benar dengan metode set() dan disetel ulang ke salah dengan metode clear(). Metode wait() memblokir hingga tandanya benar.
Berikut ini adalah metode utama dari objek Event −
- is_set():Mengembalikan True jika dan hanya jika flag internal benar.
- set():Menyetel tanda internal ke true. Semua benang merah yang menunggunya menjadi kenyataan telah terbangun. Thread yang memanggil wait() setelah flag bernilai true tidak akan diblokir sama sekali.
- clear():Menyetel ulang tanda internal ke false. Selanjutnya, thread yang memanggil wait() akan diblokir hingga set() dipanggil untuk menyetel flag internal ke true lagi.
- tunggu(waktu habis=Tidak Ada):Blokir hingga tanda internal bernilai benar. Jika tanda internal benar saat masuk, segera kembali. Jika tidak, blokir hingga thread lain memanggil set() untuk menyetel tanda ke true, atau hingga batas waktu opsional terjadi. Jika argumen batas waktu ada dan bukan Tidak Ada, argumen tersebut harus berupa angka floating point yang menentukan batas waktu operasi dalam hitungan detik.
Contoh
Kode berikut mencoba mensimulasikan arus lalu lintas yang dikendalikan oleh keadaan sinyal lalu lintas baik HIJAU atau MERAH.
Ada dua thread dalam program ini, yang menargetkan dua fungsi berbeda. Fungsi signal_state() secara berkala menyetel dan menyetel ulang peristiwa yang menunjukkan perubahan sinyal dari HIJAU ke MERAH.
Fungsi traffic_flow() menunggu acara disetel, dan menjalankan perulangan hingga acara tetap disetel.
from threading import Event, Thread
import time
terminate = False
def signal_state():
global terminate
while not terminate:
time.sleep(0.5)
print("Traffic Police Giving GREEN Signal")
event.set()
time.sleep(1)
print("Traffic Police Giving RED Signal")
event.clear()
def traffic_flow():
global terminate
num = 0
while num < 10 and not terminate:
print("Waiting for GREEN Signal")
event.wait()
print("GREEN Signal ... Traffic can move")
while event.is_set() and not terminate:
num += 1
print("Vehicle No:", num," Crossing the Signal")
time.sleep(1)
print("RED Signal ... Traffic has to wait")
event = Event()
t1 = Thread(target=signal_state)
t2 = Thread(target=traffic_flow)
t1.start()
t2.start()
# Terminate the threads after some time
time.sleep(5)
terminate = True
# join all threads to complete
t1.join()
t2.join()
print("Exiting Main Thread")
Keluaran
Saat mengeksekusi kode di atas, Anda akan mendapatkan keluaran berikut −
Waiting for GREEN Signal
Traffic Police Giving GREEN Signal
GREEN Signal ... Traffic can move
Vehicle No: 1 Crossing the Signal
Traffic Police Giving RED Signal
RED Signal ... Traffic has to wait
Waiting for GREEN Signal
Traffic Police Giving GREEN Signal
GREEN Signal ... Traffic can move
Vehicle No: 2 Crossing the Signal
Vehicle No: 3 Crossing the Signal
Traffic Police Giving RED Signal
Traffic Police Giving GREEN Signal
Vehicle No: 4 Crossing the Signal
Traffic Police Giving RED Signal
RED Signal ... Traffic has to wait
Traffic Police Giving GREEN Signal
Traffic Police Giving RED Signal
Exiting Main Thread
Objek Kondisi
Objek Condition dalam modul threading Python menyediakan mekanisme sinkronisasi yang lebih canggih. Ini memungkinkan thread menunggu pemberitahuan dari thread lain sebelum melanjutkan. Objek Kondisi selalu dikaitkan dengan kunci dan menyediakan mekanisme untuk memberi sinyal antar thread.
Berikut adalah sintaks kelas threading.Condition() −
threading.Condition(lock=None)
Di bawah ini adalah metode utama objek Kondisi −
- acquire(*args):Mendapatkan kunci yang mendasarinya. Metode ini memanggil metode yang sesuai pada kunci yang mendasarinya; nilai yang dikembalikan adalah berapa pun yang dikembalikan oleh metode tersebut.
- release():Melepaskan kunci yang mendasarinya. Metode ini memanggil metode yang sesuai pada kunci yang mendasarinya; tidak ada nilai kembalian.
- tunggu(timeout=None):Metode ini melepaskan kunci yang mendasarinya, dan kemudian memblokirnya hingga dibangunkan oleh panggilan notify() atau notify_all() untuk variabel kondisi yang sama di thread lain, atau hingga batas waktu opsional terjadi. Setelah dibangunkan atau waktunya habis, ia mendapatkan kembali kuncinya dan kembali.
- wait_for(predicate, timeout=None):Metode utilitas ini dapat memanggil wait() berulang kali hingga predikat terpenuhi, atau hingga batas waktu terjadi. Nilai kembalian adalah nilai kembalian terakhir dari predikat dan akan bernilai False jika waktu metode habis.
- notify(n=1):Metode ini membangunkan paling banyak n thread yang menunggu variabel kondisi; ini dilarang jika tidak ada thread yang menunggu.
- notify_all():Membangunkan semua thread yang menunggu pada kondisi ini. Metode ini bertindak seperti notify(), tetapi membangunkan semua thread yang menunggu, bukan satu. Jika thread pemanggil belum mendapatkan kunci saat metode ini dipanggil, RuntimeError akan dimunculkan.
Contoh
Contoh ini mendemonstrasikan bentuk sederhana komunikasi antar-thread menggunakan objek Condition dari modul threading Python. Di sini thread_a dan thread_b dikomunikasikan menggunakan objek Kondisi, thread_a menunggu hingga menerima notifikasi dari thread_b. thread_b tidur selama 2 detik sebelum memberi tahu thread_a dan kemudian selesai.
from threading import Condition, Thread
import time
c = Condition()
def thread_a():
print("Thread A started")
with c:
print("Thread A waiting for permission...")
c.wait()
print("Thread A got permission!")
print("Thread A finished")
def thread_b():
print("Thread B started")
with c:
time.sleep(2)
print("Notifying Thread A...")
c.notify()
print("Thread B finished")
Thread(target=thread_a).start()
Thread(target=thread_b).start()
Keluaran
Saat mengeksekusi kode di atas, Anda akan mendapatkan keluaran berikut −
Thread A started
Thread A waiting for permission...
Thread B started
Notifying Thread A...
Thread B finished
Thread A got permission!
Thread A finished
Contoh
Berikut adalah kode lain yang menunjukkan bagaimana objek Condition digunakan untuk menyediakan komunikasi antar thread. Dalam hal ini, thread t2 menjalankan fungsi taskB(), dan thread t1 menjalankan fungsi taskA(). Thread t1 memperoleh kondisi tersebut dan memberitahukannya.
Pada saat itu, thread t2 berada dalam status menunggu. Setelah kondisi dilepaskan, thread tunggu melanjutkan untuk menggunakan nomor acak yang dihasilkan oleh fungsi pemberitahuan.
from threading import Condition, Thread
import time
import random
numbers = []
def taskA(c):
for _ in range(5):
with c:
num = random.randint(1, 10)
print("Generated random number:", num)
numbers.append(num)
print("Notification issued")
c.notify()
time.sleep(0.3)
def taskB(c):
for i in range(5):
with c:
print("waiting for update")
while not numbers:
c.wait()
print("Obtained random number", numbers.pop())
time.sleep(0.3)
c = Condition()
t1 = Thread(target=taskB, args=(c,))
t2 = Thread(target=taskA, args=(c,))
t1.start()
t2.start()
t1.join()
t2.join()
print("Done")
Saat Anda menjalankan kode ini, output berikut akan dihasilkan −
waiting for update
Generated random number: 2
Notification issued
Obtained random number 2
Generated random number: 5
Notification issued
waiting for update
Obtained random number 5
Generated random number: 1
Notification issued
waiting for update
Obtained random number 1
Generated random number: 9
Notification issued
waiting for update
Obtained random number 9
Generated random number: 2
Notification issued
waiting for update
Obtained random number 2
Done