PYTHON CONCURRENCY
CÁC CHỦ ĐỀ
BÀI MỚI NHẤT
MỚI CẬP NHẬT

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ế.

test php

banquyen png
Bài viết này được đăng tại freetuts.net, không được copy dưới mọi hình thức.

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.

Cùng chuyên mục:

Hướng dẫn xây dựng Command-Line Interface (CLI) bằng Quo trong Python

Hướng dẫn xây dựng Command-Line Interface (CLI) bằng Quo trong Python

Hướng dẫn toàn diện về module datetime trong Python

Hướng dẫn toàn diện về module datetime trong Python

Cách truy cập và thiết lập biến môi trường trong Python

Cách truy cập và thiết lập biến môi trường trong Python

Lớp dữ liệu (Data Classes) trong Python với decorator @dataclass

Lớp dữ liệu (Data Classes) trong Python với decorator @dataclass

Từ khóa yield trong Python

Từ khóa yield trong Python

Sự khác biệt giữa sort() và sorted() trong Python

Sự khác biệt giữa sort() và sorted() trong Python

Sử dụng Poetry để quản lý dependencies trong Python

Sử dụng Poetry để quản lý dependencies trong Python

Định dạng chuỗi Strings trong Python

Định dạng chuỗi Strings trong Python

Một tác vụ phổ biến khi làm việc với danh sách trong Python

Một tác vụ phổ biến khi làm việc với danh sách trong Python

Làm việc với các biến môi trường trong Python

Làm việc với các biến môi trường trong Python

Sự khác biệt giữa set() và frozenset() trong Python

Sự khác biệt giữa set() và frozenset() trong Python

Sự khác biệt giữa iterator và iterable trong Python

Sự khác biệt giữa iterator và iterable trong Python

Cách làm việc với file tarball/tar trong Python

Cách làm việc với file tarball/tar trong Python

Chuyển đổi kiểu dữ liệu trong Python

Chuyển đổi kiểu dữ liệu trong Python

Sự khác biệt giữa toán tử == và is trong Python

Sự khác biệt giữa toán tử == và is trong Python

Làm việc với file ZIP trong Python

Làm việc với file ZIP trong Python

Cách sử dụng ThreadPoolExecutor trong Python

Cách sử dụng ThreadPoolExecutor trong Python

Sự khác biệt giữa byte objects và string trong Python

Sự khác biệt giữa byte objects và string trong Python

Xử lý độ chính xác các hàm floor, ceil, round, trunc, format  trong Python

Xử lý độ chính xác các hàm floor, ceil, round, trunc, format trong Python

Cách lặp qua nhiều list với hàm zip() trong Python

Cách lặp qua nhiều list với hàm zip() trong Python

Top