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.

Cách sử dụng Semaphore trong Python

Trong lập trình đa luồng, việc kiểm soát truy cập vào tài nguyên chia sẻ là một thách thức lớn. Nếu nhiều luồng cùng truy cập vào tài nguyên này một cách đồng thời mà không có cơ chế quản lý, sẽ dễ dẫn đến các vấn đề về đồng bộ hóa như điều kiện cạnh tranh (race conditions) và xung đột dữ liệu. Để giải quyết vấn đề này, Python cung cấp Semaphore - một công cụ đồng bộ hóa mạnh mẽ cho phép bạn giới hạn số lượng luồng có thể truy cập vào tài nguyên chia sẻ cùng lúc. Trong bài viết này, bạn sẽ học cách sử dụng Semaphore trong Python để đảm bảo rằng chỉ một số lượng nhất định các luồng có thể truy cập tài nguyên chia sẻ, giúp ngăn ngừa các vấn đề về đồng bộ hóa và đảm bảo hoạt động ổn định của chương trình.

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ề Semaphore trong Python

Semaphore trong Python là một công cụ đồng bộ hóa cho phép bạn kiểm soát việc truy cập vào một tài nguyên chia sẻ. Cơ bản, một semaphore là một bộ đếm liên kết với một khóa, giới hạn số lượng luồng có thể truy cập vào tài nguyên chia sẻ cùng lúc.

Semaphore giúp ngăn chặn các vấn đề đồng bộ hóa luồng như điều kiện cạnh tranh (race conditions), khi nhiều luồng cố gắng truy cập tài nguyên cùng lúc và làm nhiễu loạn hoạt động của nhau.

Semaphore duy trì một bộ đếm. Khi một luồng muốn truy cập tài nguyên chia sẻ, semaphore kiểm tra bộ đếm.

Bài viết này được đăng tại [free tuts .net]

Nếu bộ đếm lớn hơn không, nó giảm bộ đếm và cho phép luồng truy cập tài nguyên. Nếu bộ đếm bằng không, semaphore sẽ chặn luồng cho đến khi bộ đếm lớn hơn không.

Semaphore có hai thao tác chính:

  • Acquire: Thao tác acquire kiểm tra bộ đếm và giảm nó nếu lớn hơn không. Nếu bộ đếm bằng không, semaphore sẽ chặn luồng cho đến khi một luồng khác giải phóng semaphore.
  • Release: Thao tác release tăng bộ đếm, cho phép các luồng khác có thể acquire nó.

Sử dụng Semaphore trong Python

Để sử dụng semaphore, bạn làm theo các bước sau:

  1. Đầu tiên, import module threading:

import threading

Thứ hai, tạo một đối tượng Semaphore và chỉ định số lượng luồng có thể acquire nó cùng lúc:

semaphore = threading.Semaphore(3)
  • Trong ví dụ này, chúng ta tạo một đối tượng Semaphore chỉ cho phép tối đa ba luồng acquire nó cùng lúc.

  • Thứ ba, acquire semaphore từ một luồng bằng cách gọi phương thức acquire():

semaphore.acquire()
  • Nếu bộ đếm semaphore bằng không, luồng sẽ đợi cho đến khi một luồng khác giải phóng semaphore. Sau khi acquire semaphore, bạn có thể thực thi một đoạn mã quan trọng.

  • Cuối cùng, giải phóng semaphore sau khi chạy đoạn mã quan trọng bằng cách gọi phương thức release():

semaphore.release()

Để đảm bảo semaphore được acquire và release một cách chính xác, ngay cả khi xảy ra ngoại lệ trong khi chạy đoạn mã quan trọng, bạn có thể sử dụng câu lệnh with:

with semaphore:
    # Code trong khối này đã acquire semaphore

    # Thực hiện các thao tác trên tài nguyên chia sẻ
    # ...
    
# Semaphore được giải phóng bên ngoài khối with

Câu lệnh with sẽ acquire và release semaphore tự động, làm cho mã của bạn ít dễ bị lỗi hơn.

Ví dụ về Semaphore trong Python

Ví dụ sau đây minh họa cách sử dụng semaphore để giới hạn số lượng tải xuống đồng thời tối đa là ba bằng cách sử dụng multithreading trong Python:

import threading
import urllib.request

MAX_CONCURRENT_DOWNLOADS = 3
semaphore = threading.Semaphore(MAX_CONCURRENT_DOWNLOADS)

def download(url):
    with semaphore:
        print(f"Đang tải xuống {url}...")
        
        response = urllib.request.urlopen(url)
        data = response.read()
        
        print(f"Đã tải xong {url}")

        return data

def main():
    # Các URL để tải xuống
    urls = [
        'https://www.ietf.org/rfc/rfc791.txt',
        'https://www.ietf.org/rfc/rfc792.txt',
        'https://www.ietf.org/rfc/rfc793.txt',
        'https://www.ietf.org/rfc/rfc794.txt',
        'https://www.ietf.org/rfc/rfc795.txt',
    ]

    # Tạo các luồng cho mỗi lượt tải xuống
    threads = []
    for url in urls:
        thread = threading.Thread(target=download, args=(url,))
        threads.append(thread)
        thread.start()

    # Đợi tất cả các luồng hoàn thành
    for thread in threads:
        thread.join()

if __name__ == '__main__':
    main()

Kết quả

Đang tải xuống https://www.ietf.org/rfc/rfc791.txt...
Đang tải xuống https://www.ietf.org/rfc/rfc792.txt...
Đang tải xuống https://www.ietf.org/rfc/rfc793.txt...
Đã tải xong https://www.ietf.org/rfc/rfc792.txt
Đang tải xuống https://www.ietf.org/rfc/rfc794.txt...
Đã tải xong https://www.ietf.org/rfc/rfc791.txt
Đang tải xuống https://www.ietf.org/rfc/rfc795.txt...
Đã tải xong https://www.ietf.org/rfc/rfc793.txt
Đã tải xong https://www.ietf.org/rfc/rfc794.txt
Đã tải xong https://www.ietf.org/rfc/rfc795.txt

Giải thích chi tiết

Đầu tiên, import module threading và urllib.request:

import threading
import urllib.request

Thứ hai, tạo một đối tượng Semaphore để kiểm soát số lượng luồng có thể tải xuống đồng thời tối đa là ba:

MAX_CONCURRENT_DOWNLOADS = 3
semaphore = threading.Semaphore(MAX_CONCURRENT_DOWNLOADS)

Thứ ba, định nghĩa hàm download() để tải xuống từ một URL. Hàm download acquire và release semaphore bằng cách sử dụng câu lệnh with. Nó cũng sử dụng module urllib.request để tải dữ liệu từ một URL:

def download(url):
    with semaphore:
        print(f"Đang tải xuống {url}...")
        
        response = urllib.request.urlopen(url)
        data = response.read()
        
        print(f"Đã tải xong {url}")

        return data

Thứ tư, định nghĩa hàm main() để tạo năm luồng dựa trên danh sách URL và bắt đầu chúng để tải dữ liệu:

def main():
    # Các URL để tải xuống
    urls = [
        'https://www.ietf.org/rfc/rfc791.txt',
        'https://www.ietf.org/rfc/rfc792.txt',
        'https://www.ietf.org/rfc/rfc793.txt',
        'https://www.ietf.org/rfc/rfc794.txt',
        'https://www.ietf.org/rfc/rfc795.txt',
    ]

    # Tạo các luồng cho mỗi lượt tải xuống
    threads = []
    for url in urls:
        thread = threading.Thread(target=download, args=(url,))
        threads.append(thread)
        thread.start()

    # Đợi tất cả các luồng hoàn thành
    for thread in threads:
        thread.join()

Cuối cùng, gọi hàm main() trong phần if __name__ == '__main__':

if __name__ == '__main__':
    main()

Kết bài

Hy vọng rằng bài viết này đã giúp bạn hiểu rõ cách sử dụng semaphore trong Python để kiểm soát số lượng luồng có thể truy cập tài nguyên chia sẻ cùng lúc. Việc sử dụng phương thức acquire() để kiểm tra và giảm bộ đếm của semaphore, cũng như phương thức release() để tăng bộ đếm, là rất quan trọng để đảm bảo đồng bộ hóa. Bằng cách sử dụng câu lệnh with, bạn có thể tự động và an toàn acquirerelease semaphore, giúp mã nguồn của bạn trở nên gọn gàng và ít lỗi hơn. Sử dụng semaphore một cách hiệu quả sẽ giúp bạn tránh được các vấn đề về điều kiện cạnh tranh và xung đột dữ liệu, đảm bảo hoạt động ổn định và hiệu quả cho các ứng dụng đa luồng.

Cùng chuyên mục:

Cách thêm Progress Bar trong Python với chỉ một dòng Code

Cách thêm Progress Bar trong Python với chỉ một dòng Code

Toán tử Walrus Operator- Tính năng mới trong Python 3.8

Toán tử Walrus Operator- Tính năng mới trong Python 3.8

Cách nạp dữ liệu Machine Learning từ File trong Python

Cách nạp dữ liệu Machine Learning từ File trong Python

Hướng dẫn sử dụng Google Sheets API với Python

Hướng dẫn sử dụng Google Sheets API với Python

Xây dựng  web Python tự động hóa Twitter | Flask, Heroku, Twitter API & Google Sheets API

Xây dựng web Python tự động hóa Twitter | Flask, Heroku, Twitter API & Google Sheets API

Xây dựng Web Machine Learning đẹp mắt với Streamlit và Scikit-learn trong Python

Xây dựng Web Machine Learning đẹp mắt với Streamlit và Scikit-learn trong Python

Hướng dẫn tạo Chatbot đơn giản bằng PyTorch

Hướng dẫn tạo Chatbot đơn giản bằng PyTorch

11 mẹo và thủ thuật để viết Code Python hiệu quả hơn

11 mẹo và thủ thuật để viết Code Python hiệu quả hơn

Hướng dẫn làm ứng dụng TODO với Flask dành cho người mới bắt đầu trong Python

Hướng dẫn làm ứng dụng TODO với Flask dành cho người mới bắt đầu trong Python

Hướng dẫn viết Snake Game bằng Python

Hướng dẫn viết Snake Game bằng Python

Cách sử dụng chế độ interactive trong Python

Cách sử dụng chế độ interactive trong Python

Cách sử dụng Python Debugger với hàm breakpoint()

Cách sử dụng Python Debugger với hàm breakpoint()

Xây dựng ứng dụng Web Style Transfer với PyTorch và Streamlit

Xây dựng ứng dụng Web Style Transfer với PyTorch và Streamlit

Cách cài đặt Jupyter Notebook trong môi trường Conda và thêm Kernel

Cách cài đặt Jupyter Notebook trong môi trường Conda và thêm Kernel

Hướng dẫn xây dựng ứng dụng dự đoán giá cổ phiếu bằng Python

Hướng dẫn xây dựng ứng dụng dự đoán giá cổ phiếu bằng Python

Hướng dẫn tạo ứng dụng AI hội thoại với NVIDIA Jarvis trong Python

Hướng dẫn tạo ứng dụng AI hội thoại với NVIDIA Jarvis trong Python

Hỗ trợ Async trong Django 3.1

Hỗ trợ Async trong Django 3.1

8 mẹo tái cấu trúc Python giúp mã sạch hơn và Pythonic

8 mẹo tái cấu trúc Python giúp mã sạch hơn và Pythonic

Ý nghĩa của if __name__ ==

Ý nghĩa của if __name__ == "__main__" trong Python

Cách xóa phần tử trong danh sách Python

Cách xóa phần tử trong danh sách Python

Top