Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.
Đối tượng Threading Event trong Python
Trong lập trình đa luồng, việc giao tiếp giữa các luồng và đồng bộ hóa hoạt động của chúng là rất quan trọng để đảm bảo chương trình hoạt động hiệu quả và không gặp phải lỗi. Python cung cấp nhiều công cụ mạnh mẽ để hỗ trợ quá trình này, trong đó đối tượng Event
từ module threading
là một phương tiện hiệu quả và dễ sử dụng. Event
cho phép các luồng phối hợp hoạt động thông qua cơ chế báo hiệu, giúp một luồng có thể thông báo cho các luồng khác biết khi nào nên tiếp tục thực hiện nhiệm vụ. Bài viết này sẽ giới thiệu chi tiết về đối tượng Event
, cách sử dụng nó để giao tiếp giữa các luồng, và cung cấp các ví dụ minh họa cụ thể để bạn đọc có thể nắm bắt và áp dụng vào thực tế.
Giới thiệu về đối tượng Threading Event trong Python
Đôi khi, bạn cần giao tiếp giữa các luồng trong chương trình của mình. Để làm điều này, bạn có thể sử dụng khóa (mutex) và một biến boolean.
Tuy nhiên, Python cung cấp một cách tốt hơn để giao tiếp giữa các luồng bằng cách sử dụng lớp Event từ module threading.
Lớp Event cung cấp một cách đơn giản nhưng hiệu quả để phối hợp giữa các luồng: một luồng báo hiệu sự kiện trong khi các luồng khác chờ sự kiện đó.
Bài viết này được đăng tại [free tuts .net]
Đối tượng Event bọc một cờ boolean có thể được đặt (True) hoặc xóa (False). Nhiều luồng có thể chờ sự kiện được đặt trước khi tiếp tục hoặc có thể đặt lại sự kiện về trạng thái xóa.
Các bước sử dụng đối tượng Event
Nhập Event từ module threading:
from threading import Event
Tạo một đối tượng Event mới:
event = Event()
Mặc định, sự kiện không được đặt (xóa). Phương thức is_set() của đối tượng event sẽ trả về False:
if event.is_set(): # ...
Đặt một sự kiện bằng phương thức set():
event.clear()
Các luồng có thể chờ sự kiện được đặt thông qua phương thức wait():
event.wait()
Phương thức wait() sẽ chặn luồng hiện tại cho đến khi sự kiện được đặt. Bạn cũng có thể chỉ định thời gian chờ thông qua tham số timeout:
event.wait(timeout=5) # chờ trong 5 giây
Ví dụ về sử dụng Threading Event trong Python
Ví dụ sau minh họa cách sử dụng đối tượng Event để giao tiếp giữa các luồng:
from threading import Thread, Event from time import sleep def task(event: Event, id: int) -> None: print(f'Thread {id} started. Waiting for the signal....') event.wait() print(f'Received signal. The thread {id} was completed.') def main() -> None: event = Event() t1 = Thread(target=task, args=(event,1)) t2 = Thread(target=task, args=(event,2)) t1.start() t2.start() print('Blocking the main thread for 3 seconds...') sleep(3) event.set() if __name__ == '__main__': main()
Cách hoạt động của mã:
Định nghĩa hàm task() nhận một đối tượng Event và một số nguyên:
def task(event: Event, id: int) -> None: print(f'Thread {id} started. Waiting for the signal....') event.wait() print(f'Received signal. The thread {id} was completed.')
Trong hàm task(), chúng ta gọi phương thức wait() của đối tượng event để chờ sự kiện được đặt bởi luồng chính.
Tạo đối tượng Event bên trong hàm main():
event = Event()
Tạo hai luồng con thực thi hàm task() với cùng đối tượng event và id khác nhau:
t1 = Thread(target=task, args=(event,1)) t2 = Thread(target=task, args=(event,2))
Bắt đầu cả hai luồng:
t1.start() t2.start()
Chặn luồng chính trong 3 giây:
sleep(3)
Vì hàm task() gọi phương thức wait() của đối tượng event, cả hai luồng t1 và t2 sẽ chờ sự kiện được đặt trước khi tiếp tục.
Đặt sự kiện bằng cách gọi phương thức set() từ luồng chính:
event.set()
Cả hai luồng t1 và t2 sẽ được thông báo và tiếp tục thực thi cho đến khi kết thúc.
Ví dụ thực tế về sử dụng Threading Event trong Python
Ví dụ sau minh họa cách sử dụng threading event để đồng bộ hóa giữa hai luồng:
- Luồng thứ nhất tải xuống một tệp văn bản từ URL
https://www.ietf.org/rfc/rfc793.txt
, khi hoàn thành, nó thông báo cho luồng thứ hai để đếm số từ trong tệp đã tải xuống. - Luồng thứ hai bắt đầu và chờ tín hiệu hoàn thành từ luồng thứ nhất. Khi nhận được tín hiệu, nó bắt đầu đếm số từ trong tệp đã tải xuống.
from threading import Thread, Event from urllib import request def download_file(url, event): # Tải tệp từ URL print(f"Downloading file from {url}...") filename, _ = request.urlretrieve(url, "rfc793.txt") # Tệp đã được tải xuống, đặt sự kiện event.set() def process_file(event): print("Waiting for the file to be downloaded...") event.wait() # Chờ sự kiện được đặt # Tệp đã được tải xuống, bắt đầu xử lý print("File download completed. Starting file processing...") # Đếm số từ trong tệp word_count = 0 with open("rfc793.txt", "r") as file: for line in file: words = line.split() word_count += len(words) # In số từ trong tệp print(f"Number of words in the file: {word_count}") def main(): # Tạo đối tượng Event event = Event() # Tạo và bắt đầu luồng tải tệp download_thread = Thread(target=download_file, args=("https://www.ietf.org/rfc/rfc793.txt", event)) download_thread.start() # Tạo và bắt đầu luồng xử lý tệp process_thread = Thread(target=process_file, args=(event,)) process_thread.start() # Chờ cả hai luồng hoàn thành download_thread.join() process_thread.join() print("Main thread finished.") if __name__ == '__main__': main()
Kết bài
Trong lập trình đa luồng, việc sử dụng đối tượng Event
của lớp threading
mang lại nhiều lợi ích cho việc giao tiếp và đồng bộ hóa giữa các luồng. Như đã trình bày, bạn có thể sử dụng các phương thức set()
, clear()
, is_set()
, và wait()
để kiểm soát và quản lý sự kiện giữa các luồng một cách dễ dàng và hiệu quả.
Phương thức set()
cho phép bạn kích hoạt sự kiện, báo hiệu cho các luồng khác biết rằng chúng có thể tiếp tục thực hiện nhiệm vụ của mình. Phương thức clear()
giúp xóa sự kiện, đưa nó về trạng thái ban đầu để sẵn sàng cho lần sử dụng tiếp theo. Với is_set()
, bạn có thể kiểm tra xem sự kiện đã được kích hoạt hay chưa, và wait()
sẽ giúp các luồng chờ đợi cho đến khi sự kiện được đặt.
Những kiến thức này không chỉ giúp bạn viết các chương trình đa luồng mạnh mẽ và hiệu quả hơn, mà còn giúp bạn tránh được các vấn đề tiềm ẩn như deadlock và race condition. Hy vọng rằng bài viết đã cung cấp cho bạn một cái nhìn rõ ràng và đầy đủ về cách sử dụng Event
trong Python, giúp bạn tự tin hơn trong việc lập trình đa luồng.