Khóa học python

Synchronizing Threads trong Python

0 phút đọc

Trong lập trình đa luồng (multithreading), việc đồng bộ hóa các thread là rất quan trọng để đảm bảo rằng các thread hoạt động một cách an toàn và hiệu quả khi truy cập vào các tài nguyên chia sẻ. Bài viết này sẽ hướng dẫn chi tiết về cách đồng bộ hóa các thread trong Python, kèm theo các ví dụ minh họa cụ thể.

Giới thiệu về Synchronizing Threads

Tại sao cần đồng bộ hóa các thread?

Khi nhiều thread cùng truy cập và thay đổi một tài nguyên chia sẻ (như biến, danh sách, file, v.v.), có thể xảy ra các vấn đề như race condition, deadlock, và data corruption. Đồng bộ hóa các thread giúp đảm bảo rằng chỉ một thread có thể truy cập vào tài nguyên chia sẻ tại một thời điểm, ngăn chặn các vấn đề này.

Các cơ chế đồng bộ hóa trong Python

Python cung cấp nhiều cơ chế đồng bộ hóa để quản lý truy cập đồng thời vào các tài nguyên chia sẻ, bao gồm:

  • Lock (Khóa)
  • RLock (Reentrant Lock)
  • Semaphore
  • Event
  • Condition
  • Barrier

Sử dụng Lock để đồng bộ hóa các thread

Lock là gì?

Lock là một cơ chế đồng bộ hóa đơn giản cho phép một thread chiếm quyền truy cập vào tài nguyên chia sẻ, ngăn chặn các thread khác truy cập vào tài nguyên đó cho đến khi lock được giải phóng.

Ví dụ về sử dụng Lock

Dưới đây là một ví dụ về việc sử dụng lock để đồng bộ hóa các thread khi truy cập vào một biến chia sẻ.

import threading

# Biến chia sẻ
shared_counter = 0

# Tạo một lock
lock = threading.Lock()

def increment_counter():
    global shared_counter
    for _ in range(100000):
        with lock:
            shared_counter += 1

# Tạo và bắt đầu các thread
threads = []
for _ in range(10):
    thread = threading.Thread(target=increment_counter)
    threads.append(thread)
    thread.start()

# Chờ các thread hoàn thành
for thread in threads:
    thread.join()

print(f"Final counter value: {shared_counter}")

Output:

Final counter value: 1000000

Sử dụng RLock để đồng bộ hóa các thread

RLock là gì?

RLock (Reentrant Lock) là một loại lock cho phép một thread có thể chiếm quyền truy cập vào tài nguyên chia sẻ nhiều lần mà không bị khóa chính nó. Điều này hữu ích khi một thread cần gọi lại một hàm đã chiếm lock.

Ví dụ về sử dụng RLock

Dưới đây là một ví dụ về việc sử dụng RLock để đồng bộ hóa các thread.

import threading

# Biến chia sẻ
shared_counter = 0

# Tạo một RLock
rlock = threading.RLock()

def increment_counter():
    global shared_counter
    for _ in range(100000):
        with rlock:
            shared_counter += 1

# Tạo và bắt đầu các thread
threads = []
for _ in range(10):
    thread = threading.Thread(target=increment_counter)
    threads.append(thread)
    thread.start()

# Chờ các thread hoàn thành
for thread in threads:
    thread.join()

print(f"Final counter value: {shared_counter}")

Output:

Final counter value: 1000000

Sử dụng Semaphore để đồng bộ hóa các thread

Semaphore là gì?

Semaphore là một cơ chế đồng bộ hóa cho phép giới hạn số lượng thread có thể truy cập vào tài nguyên chia sẻ cùng một lúc. Semaphore có một bộ đếm, và mỗi khi một thread chiếm quyền truy cập, bộ đếm giảm đi một. Khi bộ đếm về 0, các thread khác phải chờ cho đến khi bộ đếm tăng lên.

Ví dụ về sử dụng Semaphore

Dưới đây là một ví dụ về việc sử dụng semaphore để đồng bộ hóa các thread.

import threading
import time

# Tạo một semaphore với giá trị ban đầu là 3
semaphore = threading.Semaphore(3)

def access_resource(thread_id):
    with semaphore:
        print(f"Thread {thread_id} is accessing the resource")
        time.sleep(2)
        print(f"Thread {thread_id} has finished accessing the resource")

# Tạo và bắt đầu các thread
threads = []
for i in range(10):
    thread = threading.Thread(target=access_resource, args=(i,))
    threads.append(thread)
    thread.start()

# Chờ các thread hoàn thành
for thread in threads:
    thread.join()

Output:

Thread 0 is accessing the resource
Thread 1 is accessing the resource
Thread 2 is accessing the resource
Thread 0 has finished accessing the resource
Thread 3 is accessing the resource
Thread 1 has finished accessing the resource
Thread 4 is accessing the resource
Thread 2 has finished accessing the resource
Thread 5 is accessing the resource
Thread 3 has finished accessing the resource
Thread 6 is accessing the resource
Thread 4 has finished accessing the resource
Thread 7 is accessing the resource
Thread 5 has finished accessing the resource
Thread 8 is accessing the resource
Thread 6 has finished accessing the resource
Thread 9 is accessing the resource
Thread 7 has finished accessing the resource
Thread 8 has finished accessing the resource
Thread 9 has finished accessing the resource

Sử dụng Event để đồng bộ hóa các thread

Event là gì?

Event là một cơ chế đồng bộ hóa cho phép một thread chờ một sự kiện cụ thể xảy ra. Một event có thể ở trạng thái "set" hoặc "clear". Khi event ở trạng thái "set", các thread đang chờ event sẽ tiếp tục thực thi.

Ví dụ về sử dụng Event

Dưới đây là một ví dụ về việc sử dụng event để đồng bộ hóa các thread.

import threading
import time

# Tạo một event
event = threading.Event()

def wait_for_event(thread_id):
    print(f"Thread {thread_id} is waiting for the event")
    event.wait()
    print(f"Thread {thread_id} has received the event")

def set_event():
    time.sleep(3)
    print("Setting the event")
    event.set()

# Tạo và bắt đầu các thread
threads = []
for i in range(5):
    thread = threading.Thread(target=wait_for_event, args=(i,))
    threads.append(thread)
    thread.start()

# Tạo và bắt đầu thread để set event
event_thread = threading.Thread(target=set_event)
event_thread.start()

# Chờ các thread hoàn thành
for thread in threads:
    thread.join()
event_thread.join()

Output:

Thread 0 is waiting for the event
Thread 1 is waiting for the event
Thread 2 is waiting for the event
Thread 3 is waiting for the event
Thread 4 is waiting for the event
Setting the event
Thread 0 has received the event
Thread 1 has received the event
Thread 2 has received the event
Thread 3 has received the event
Thread 4 has received the event

Sử dụng Condition để đồng bộ hóa các thread

Condition là gì?

Condition là một cơ chế đồng bộ hóa cho phép các thread chờ một điều kiện cụ thể và thông báo cho các thread khác khi điều kiện đó được thỏa mãn. Condition thường được sử dụng kết hợp với lock.

Ví dụ về sử dụng Condition

Dưới đây là một ví dụ về việc sử dụng condition để đồng bộ hóa các thread.

import threading
import time

# Tạo một condition
condition = threading.Condition()

def consumer():
    with condition:
        print("Consumer is waiting")
        condition.wait()
        print("Consumer has consumed the item")

def producer():
    with condition:
        print("Producer is producing an item")
        time.sleep(2)
        print("Producer has produced an item")
        condition.notify()

# Tạo và bắt đầu các thread
consumer_thread = threading.Thread(target=consumer)
producer_thread = threading.Thread(target=producer)

consumer_thread.start()
producer_thread.start()

# Chờ các thread hoàn thành
consumer_thread.join()
producer_thread.join()

Output:

Consumer is waiting
Producer is producing an item
Producer has produced an item
Consumer has consumed the item

Sử dụng Barrier để đồng bộ hóa các thread

Barrier là gì?

Barrier là một cơ chế đồng bộ hóa cho phép một nhóm các thread chờ nhau tại một điểm nhất định trước khi tiếp tục thực thi. Barrier đảm bảo rằng tất cả các thread trong nhóm đều đã đến điểm chờ trước khi bất kỳ thread nào tiếp tục.

Ví dụ về sử dụng Barrier

Dưới đây là một ví dụ về việc sử dụng barrier để đồng bộ hóa các thread.

import threading
import time

# Tạo một barrier cho 3 thread
barrier = threading.Barrier(3)

def worker(thread_id):
    print(f"Thread {thread_id} is waiting at the barrier")
    time.sleep(thread_id)
    barrier.wait()
    print(f"Thread {thread_id} has passed the barrier")

# Tạo và bắt đầu các thread
threads = []
for i in range(3):
    thread = threading.Thread(target=worker, args=(i,))
    threads.append(thread)
    thread.start()

# Chờ các thread hoàn thành
for thread in threads:
    thread.join()

Output:

Thread 0 is waiting at the barrier
Thread 1 is waiting at the barrier
Thread 2 is waiting at the barrier
Thread 0 has passed the barrier
Thread 1 has passed the barrier
Thread 2 has passed the barrier

Các Thực Hành Tốt Nhất khi Đồng Bộ Hóa Các Thread

Sử dụng Lock để Bảo Vệ Tài Nguyên Chia Sẻ

Sử dụng lock để bảo vệ các tài nguyên chia sẻ và ngăn chặn các vấn đề liên quan đến truy cập đồng thời.

import threading

lock = threading.Lock()

def safe_increment(counter):
    with lock:
        counter.value += 1

Tránh Deadlock

Tránh deadlock bằng cách đảm bảo rằng các thread không chờ nhau vô thời hạn. Sử dụng timeout khi cần thiết.

import threading

lock1 = threading.Lock()
lock2 = threading.Lock()

def thread1():
    with lock1:
        with lock2:
            pass

def thread2():
    with lock2:
        with lock1:
            pass

# Tạo và bắt đầu các thread
t1 = threading.Thread(target=thread1)
t2 = threading.Thread(target=thread2)

tstart()
tstart()

# Chờ các thread hoàn thành
tjoin()
tjoin()

Sử dụng Condition để Đồng Bộ Hóa Các Tác Vụ Phức Tạp

Sử dụng condition để đồng bộ hóa các tác vụ phức tạp và quản lý việc chờ đợi và thông báo giữa các thread.

import threading

condition = threading.Condition()

def consumer():
    with condition:
        condition.wait()
        # Thực hiện các tác vụ sau khi nhận được thông báo
        pass

def producer():
    with condition:
        # Thực hiện các tác vụ trước khi thông báo
        condition.notify()

Kết luận

Đồng bộ hóa các thread là một kỹ năng quan trọng trong lập trình đa luồng để đảm bảo rằng các thread hoạt động một cách an toàn và hiệu quả khi truy cập vào các tài nguyên chia sẻ. Bằng cách sử dụng các cơ chế đồng bộ hóa như lock, RLock, semaphore, event, condition, và barrier, bạn có thể quản lý truy cập đồng thời và ngăn chặn các vấn đề như race condition, deadlock, và data corruption. Hy vọng rằng các ví dụ và hướng dẫn trong bài viết này sẽ giúp bạn hiểu rõ hơn về cách đồng bộ hóa các thread trong Python và áp dụng chúng vào các dự án lập trình của mình.

Avatar
Được viết bởi

TechMely Team

Gợi ý câu hỏi phỏng vấn

entry

Liệt kê các kiểu dữ liệu trong Python?

entry

Biến cục bộbiến toàn cục trong Python là gì?

entry

Trong Python có những built-in types nào?

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào

Khoá học javascript từ cơ bản đến chuyên sâuYoutube Techmely