Python - Multithreading (Tiếng Việt)

Xin chào các nhà vua Python tương lai! Hôm nay, chúng ta sẽ bắt đầu hành trình hấp dẫn vào thế giới đa luồng trong Python. Đừng lo nếu bạn mới bắt đầu học lập trình; tôi sẽ là người hướng dẫn bạn, và chúng ta sẽ khám phá chủ đề này bước từng bước. Vậy, hãy cầm chắc chiếc cây cơ (bàn phím) của bạn và bắt đầu!

Python - Multithreading

Đa Luồng là gì?

Trước khi chúng ta bắt đầu làm việc với luồng trong Python, hãy hiểu rõ về đa luồng là gì. Hãy tưởng tượng bạn là một đầu bếp trong một nhà bếp rất buồn. Nếu bạn nấu cơ một mình, bạn chỉ có thể làm một công việc tại một thời điểm - cắt rau, sau đó nấu nước, sau đó xào thịt. Nhưng điều gì xảy ra nếu bạn có nhiều tay để làm các công việc khác nhau đồng thời? Đó chính là điều mà đa luồng làm cho chương trình của chúng ta!

Đa luồng cho phép một chương trình thực hiện nhiều nhiệm vụ đồng thời trong một tiến trình duy nhất. Nó như có nhiều đầu bếp (luồng) làm việc cùng nhau trong cùng một nhà bếp (tiến trình) để chuẩn bị một bữa ăn ngon (kết quả chương trình) nhanh hơn và hiệu quả hơn.

So sánh với Tiến trình

Bây giờ, bạn có thể hỏi, "Nhưng thầy, tôi đã nghe về tiến trình cũng rồi. Luồng và tiến trình có khác nhau như thế nào?" Câu hỏi tuyệt vời! Hãy phân tích:

  1. Sử dụng tài nguyên: Luồng giống như các anh em chia sẻ một phòng (không gian bộ nhớ), trong khi tiến trình giống như các hàng xóm có nhà riêng. Luồng nhẹ hơn và chia sẻ tài nguyên, làm cho nó hiệu quả hơn cho một số nhiệm vụ.

  2. Giao tiếp: Luồng có thể dễ dàng trò chuyện bằng cách chia sẻ biến, trong khi tiến trình cần sử dụng các "điện thoại" đặc biệt (giao tiếp giữa tiến trình) để nói chuyện với nhau.

  3. Chi phí: Tạo và quản lý luồng thường nhanh hơn và yêu cầu ít tài nguyên hệ thống hơn so với tiến trình.

  4. Phức tạp: Mặc dù luồng có thể làm cho chương trình của bạn nhanh hơn, nhưng nó cũng giới thiệu phức tạp. Nó như quay búa - vui và hiệu quả khi làm đúng, nhưng bạn có thể rơi búa nếu không cẩn thận!

Các Mô-đun Xử lý Luồng trong Python

Python, là ngôn ngữ dũng cảm như vậy, cung cấp cho chúng ta nhiều mô-đun để làm việc với luồng. Có hai mô-đun chính là:

  1. threading: Đây là giao diện cao cấp cho việc làm việc với luồng. Nó như người hướng dẫn thân thiện của học phương pháp giúp bạn làm nhiều công việc nặng.

  2. _thread: Đây là giao diện thấp cấp. Nó như một cuốn sách phép cổ - mạnh mẽ nhưng yêu cầu nhiều kỹ năng để sử dụng đúng.

Đối với hành trình ma thuật hôm nay, chúng ta sẽ tập trung vào mô-đun threading, vì nó dễ hiểu hơn và được sử dụng nhiều.

Khởi tạo Luồng Mới

Bây giờ, hãy chúc mừng luồng đầu tiên của chúng ta! Dưới đây là cách chúng ta tạo và khởi động một luồng mới:

import threading
import time

def in_numbers():
    for i in range(5):
        time.sleep(1)
        print(f"Luồng 1: {i}")

# Tạo một luồng mới
thread1 = threading.Thread(target=in_numbers)

# Khởi động luồng
thread1.start()

# Luồng chính tiếp tục thực hiện
for i in range(5):
    time.sleep(1)
    print(f"Luồng chính: {i}")

# Đợi luồng1 hoàn thành
thread1.join()

print("Hoàn thành tất cả!")

Hãy phân tích lời khai báo ma thuật này:

  1. Chúng ta nhập các mô-đun threadingtime.
  2. Chúng ta định nghĩa một hàm in_numbers() sẽ được thực hiện bởi luồng của chúng ta.
  3. Chúng ta tạo một đối tượng luồng mới, xác định hàm nó nên chạy.
  4. Chúng ta khởi động luồng bằng cách sử dụng phương thức start().
  5. Luồng chính tiếp tục thực hiện vòng lặp của mình.
  6. Chúng ta sử dụng join() để đợi luồng của chúng ta hoàn thành trước khi kết thúc chương trình.

Khi bạn chạy điều này, bạn sẽ thấy các số từ cả hai luồng kết hợp, minh họa việc thực hiện đồng thời!

Đồng bộ hóa Luồng

Bây giờ, tưởng tượng các đầu bếp trợ lý của chúng ta cố gắng sử dụng cùng một dao vào cùng một thời điểm - hỗn loạn, phải không? Đây là nơi đồng bộ hóa luồng đến. Chúng ta sử dụng khóa để đảm bảo rằng chỉ một luồng có thể truy cập một tài nguyên chia sẻ tại một thời điểm.

Dưới đây là một ví dụ:

import threading
import time

# Tài nguyên chia sẻ
số = 0
khóa = threading.Lock()

def tăng_số():
    global số
    for _ in range(100000):
        khóa.acquire()
        số += 1
        khóa.release()

# Tạo hai luồng
thread1 = threading.Thread(target=tăng_số)
thread2 = threading.Thread(target=tăng_số)

# Khởi động các luồng
thread1.start()
thread2.start()

# Đợi cả hai luồng hoàn thành
thread1.join()
thread2.join()

print(f"Giá trị số cuối cùng: {số}")

Trong ví dụ này, chúng ta sử dụng một khóa để đảm bảo rằng chỉ một luồng có thể tăng số tại một thời điểm, ngăn chặn tình trạng cuộc đua.

Hàng đợi Ưu tiên Đa luồng

Cuối cùng nhưng không kém phần quan trọng, hãy xem xét một ứng dụng thực tế của đa luồng - hàng đợi ưu tiên. Tưởng tượng một phòng khám cấp cứu nơi bệnh nhân được điều trị dựa trên mức độ nghiêm trọng của tình trạng của họ, không chỉ thời gian đến.

import threading
import queue
import time
import random

# Tạo một hàng đợi ưu tiên
task_queue = queue.PriorityQueue()

def worker():
    while True:
        priority, task = task_queue.get()
        print(f"Xử lý nhiệm vụ: {task} (Ưu tiên: {priority})")
        time.sleep(random.uniform(0.1, 0.5))  # Mô phỏng công việc
        task_queue.task_done()

# Tạo và khởi động các luồng công việc
for _ in range(3):
    thread = threading.Thread(target=worker, daemon=True)
    thread.start()

# Thêm các nhiệm vụ vào hàng đợi
for i in range(10):
    priority = random.randint(1, 5)
    task = f"Nhiệm vụ {i}"
    task_queue.put((priority, task))

# Đợi tất cả các nhiệm vụ hoàn thành
task_queue.join()
print("Tất cả các nhiệm vụ đã hoàn thành!")

Ví dụ này minh họa cách mà nhiều luồng có thể làm việc cùng nhau để xử lý các nhiệm vụ từ một hàng đợi ưu tiên một cách hiệu quả.

Kết luận

Xin chúc mừng, các nhà vua Python trẻ! Bạn đã bước ra đầu tiên vào thế giới ma thuật đa luồng. Hãy nhớ, với quyền lớn đến đến trách nhiệm lớn - sử dụng luồng một cách khôn ngoan, và họ sẽ làm cho chương trình của bạn nhanh hơn và hiệu quả hơn.

Dưới đây là bảng tóm tắt các phương thức chính về luồng mà chúng ta đã trình bày:

Phương thức Mô tả
Thread(target=function) Tạo một luồng mới để chạy hàm được chỉ định
start() Khởi động hoạt động của luồng
join() Đợi luồng hoàn thành
Lock() Tạo một khóa để đồng bộ hóa luồng
acquire() Thuê khóa
release() Giải phóng khóa

Hãy tiếp tục tập luyện, giữ được sự thích thú và sớm bạn sẽ làm nhạc sống các luồng như một maestro Python chuyên nghiệp! Chúc bạn mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi mãi

Credits: Image by storyset