Hướng dẫn sử dụng đa luồng trong Python
Mục lục
- Giới thiệu về đa luồng trong Python
- Giới thiệu về khóa thông dịch toàn cục
- Sử dụng mô-đun threading trong Python
- Ví dụ cơ bản về đa luồng trong Python
- Sử dụng thời gian chờ để tạo sự trễ
- Lưu ý về vòng lặp vô hạn trong đa luồng
- Sử dụng đa luồng để xử lý đầu vào người dùng
- Đặt một luồng là luồng Daemon
- Truyền đối số và thực hiện nhiều luồng
- Đợi các luồng hoàn thành
Giới thiệu về đa luồng trong Python
Trong Python, đa luồng thực chất không có sẵn với ủy quyền thực thi CPython thông dịch toàn cục. Điều này xuất phát từ việc khóa thông dịch toàn cục (global interpreter lock - GIL) mà chúng ta sẽ giải thích trong phần tiếp theo. Tuy nhiên, chúng ta vẫn có thể sử dụng đa luồng giả lập bằng cách sử dụng mô-đun threading.
Giới thiệu về khóa thông dịch toàn cục
Khóa thông dịch toàn cục (GIL) trong Python là một cơ chế có thể chặn việc thực thi đa luồng đồng thời trên các bộ xử lý đa nhân. GIL chỉ cho phép một luồng hoạt động tại một thời điểm duy nhất, dẫn đến việc không thể tận dụng được tối đa tiềm năng song song của các bộ xử lý đa nhân.
Sử dụng mô-đun threading trong Python
Mô-đun threading trong Python cung cấp các công cụ cần thiết để tạo và quản lý các luồng trong một chương trình. Để sử dụng mô-đun này, chúng ta chỉ cần nhập thư viện threading bằng cách sử dụng lệnh import threading
.
Ví dụ cơ bản về đa luồng trong Python
Để hiểu rõ hơn về cách sử dụng đa luồng trong Python, chúng ta sẽ tạo một ví dụ đơn giản. Trong ví dụ này, chúng ta sẽ tạo hai luồng: một luồng sẽ in các số từ 1 đến 5, và một luồng khác sẽ chờ sự nhập vào từ người dùng để dừng chương trình.
import threading
def print_numbers():
for i in range(1, 6):
print(i)
def get_user_input():
input("Press Enter to quit")
# Tạo các luồng
thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=get_user_input)
# Khởi động các luồng
thread1.start()
thread2.start()
# Chờ các luồng hoàn thành
thread1.join()
thread2.join()
Sử dụng thời gian chờ để tạo sự trễ
Trong Python, chúng ta có thể sử dụng hàm time.sleep()
để tạo sự trễ trong mã của mình. Hàm này cho phép chúng ta tạm dừng thực thi chương trình trong một khoảng thời gian nhất định.
import threading
import time
def print_numbers():
for i in range(1, 6):
time.sleep(1)
print(i)
# Tạo luồng và khởi chạy
thread = threading.Thread(target=print_numbers)
thread.start()
Lưu ý về vòng lặp vô hạn trong đa luồng
Khi sử dụng đa luồng trong Python, bạn cần cẩn thận với việc sử dụng vòng lặp vô hạn trong các luồng của mình. Nếu một luồng không bao giờ kết thúc hoặc thoát khỏi vòng lặp vô hạn, chương trình của bạn sẽ không bao giờ kết thúc.
import threading
def infinite_loop():
while True:
print("This is an infinite loop")
# Tạo luồng và khởi chạy
thread = threading.Thread(target=infinite_loop)
thread.start()
Sử dụng đa luồng để xử lý đầu vào người dùng
Một trong những ứng dụng phổ biến của đa luồng trong Python là xử lý đầu vào từ người dùng mà không bị chặn lại. Bằng cách sử dụng đa luồng, bạn có thể đợi người dùng nhập và vẫn cho phép chương trình tiếp tục thực thi các tác vụ khác.
import threading
def get_user_input():
input("Press Enter to quit")
# Tạo luồng và khởi chạy
thread = threading.Thread(target=get_user_input)
thread.start()
Đặt một luồng là luồng Daemon
Trong Python, bạn có thể đặt các luồng thành luồng Daemon bằng cách đặt thuộc tính daemon
của luồng thành True
. Một luồng Daemon sẽ dừng khi tất cả các luồng chính hoàn thành.
import threading
def print_numbers():
for i in range(1, 6):
print(i)
# Tạo luồng và đặt thành luồng Daemon
thread = threading.Thread(target=print_numbers)
thread.daemon = True
# Khởi chạy luồng
thread.start()
Truyền đối số và thực hiện nhiều luồng
Trong Python, bạn có thể truyền đối số cho các luồng bằng cách sử dụng tham số args
và truyền một tuple các giá trị. Sau đó, bạn có thể sử dụng các giá trị đó trong luồng của mình.
import threading
def print_text(text):
print(text)
# Tạo luồng và truyền đối số
thread = threading.Thread(target=print_text, args=("Hello, World!",))
# Khởi chạy luồng
thread.start()
Đợi các luồng hoàn thành
Trong một chương trình Python sử dụng nhiều luồng, bạn có thể sử dụng phương thức join()
để đợi tất cả các luồng hoàn thành trước khi tiếp tục thực thi mã chính.
import threading
def print_numbers():
for i in range(1, 6):
print(i)
# Tạo luồng và khởi chạy
thread = threading.Thread(target=print_numbers)
thread.start()
# Đợi luồng hoàn thành
thread.join()
Nhược điểm:
- Không sử dụng được đa luồng thực sự do sự tồn tại của khóa thông dịch toàn cục.
- Xử lý đa luồng có thể phức tạp và dễ dẫn đến các vấn đề về hoạt động của các luồng. Điều này có thể gây ra sự kém hiệu quả và khó khăn trong việc gỡ lỗi.
Ưu điểm:
- Đa luồng giả lập trong Python vẫn hữu ích khi bạn cần xử lý các tác vụ giao tiếp mạng, tác vụ I/O chậm, hoặc các tác vụ không chặn.
- Nếu bạn cần tận dụng song song các bộ xử lý đa nhân, bạn có thể sử dụng các thư viện khác như
multiprocessing
thay vì đa luồng.