PHP
Python

Trang chủ

Tìm hiểu chi tiết về đa luồng trong Python

Ngôn ngữ Python là một ngôn ngữ lập trình đa mục đích, nổi tiếng với cú pháp dễ đọc, dễ học và tính ứng dụng cao. Trong lĩnh vực phát triển web, Python thường được sử dụng thông qua các framework như Django và Flask để xây dựng các ứng dụng web mạnh mẽ, bảo mật và dễ mở rộng. Trong chuyên mục này, Vietnix không chỉ cung cấp kiến thức nền tảng về ngôn ngữ Python mà còn hướng dẫn chi tiết cách xây dựng các ứng dụng web thực tế, sử dụng các framework phổ biến và áp dụng các kỹ thuật tiên tiến. Vietnix cam kết liên tục cập nhật những bài viết mới nhất về các tính năng mới của Python, các thư viện hỗ trợ hữu ích và những phương pháp tốt nhất, giúp bạn khai thác tối đa sức mạnh của Python và hoàn thiện kỹ năng lập trình web của mình.
html
CSS
javascript
sql
python
php
c
c++
bootstrap
react
mysql
reactjs
vuejs
Javascript Tutorials
15/03/2025
19 phút đọc
Theo dõi Vietnix trên

Tìm hiểu chi tiết về đa luồng trong Python

Đa luồng trong Python (Multithreading) là kỹ thuật cho phép một chương trình thực thi nhiều luồng (threads) cùng lúc, giúp tận dụng tối đa tài nguyên của CPU. Việc sử dụng đa luồng giúp cải thiện hiệu suất, tăng tốc độ xử lý và tối ưu hóa các tác vụ I/O như đọc/ghi file, gửi yêu cầu mạng. Trong bài viết này, mình sẽ giới thiệu chi tiết cách hoạt động của đa luồng trong Python, các tình huống áp dụng phù hợp và những lưu ý quan trọng khi triển khai.

Những điểm chính

  • Khái niệm: Hiểu rõ khái niệm và cách thức hoạt động của đa luồng, cũng như lý do tại sao nó quan trọng trong lập trình Python.
  • So sánh với các quy trình: Nắm được sự khác biệt giữa luồng (thread) và quy trình (process) để lựa chọn phương pháp xử lý phù hợp.
  • Các module xử lý luồng trong Python: Tìm hiểu về các module như _threadthreading, cách chúng hỗ trợ lập trình đa luồng hiệu quả.
  • Cách tạo luồng mới trong Python: Biết cách khởi tạo và quản lý luồng bằng các phương pháp khác nhau, giúp tối ưu hóa hiệu suất chương trình.
  • Đồng bộ hóa các luồng: Hiểu cách đồng bộ hóa dữ liệu giữa các luồng để tránh xung đột và đảm bảo tính toàn vẹn.
  • Hàng đợi ưu tiên đa luồng: Áp dụng cơ chế hàng đợi để quản lý các tác vụ đa luồng một cách hiệu quả.
  • Vietnix – Nhà cung cấp dịch vụ lưu trữ tốc độ cao: Khám phá giải pháp lưu trữ tối ưu từ Vietnix, hỗ trợ vận hành website, ứng dụng nhanh, ổn định và bảo mật.
  • Câu hỏi thường gặp: Giải đáp các thắc mắc phổ biến về lập trình đa luồng trong Python, giúp bạn nắm vững kiến thức và áp dụng hiệu quả.

Đa luồng trong Python là gì?

Đa luồng trong Python là một kỹ thuật cho phép chạy nhiều luồng (threads) đồng thời trong một tiến trình, còn được gọi là lập trình song song dựa trên luồng. Kỹ thuật này giúp chương trình thực hiện nhiều tác vụ cùng lúc, nâng cao hiệu suất và khả năng phản hồi.

Đa luồng trong Python là một kỹ thuật cho phép chạy nhiều luồng (threads) đồng thời trong một tiến trình, còn được gọi là lập trình song song dựa trên luồng
Đa luồng trong Python là một kỹ thuật cho phép chạy nhiều luồng (threads) đồng thời trong một tiến trình, còn được gọi là lập trình song song dựa trên luồng

Đa luồng đặc biệt hữu ích khi xử lý nhiều tác vụ I/O như đọc ghi dữ liệu, tải tệp tin hoặc gửi yêu cầu mạng mà không làm gián đoạn quá trình xử lý chính. Thay vì thực thi tuần tự từng dòng lệnh, chương trình có thể chia nhỏ công việc thành nhiều luồng chạy song song, giúp tối ưu thời gian xử lý. Tuy nhiên, do GIL (Global Interpreter Lock) trong Python, đa luồng không phù hợp với các tác vụ tính toán nặng. Trong trường hợp này, bạn sử dụng đa tiến trình (multiprocessing) sẽ mang lại hiệu quả tốt hơn.

So sánh với các quy trình

Hệ điều hành có khả năng quản lý nhiều quy trình (process) cùng lúc bằng cách cấp phát bộ nhớ riêng cho từng quy trình. Điều này đảm bảo rằng một quy trình không thể truy cập hoặc ghi đè dữ liệu của quy trình khác, giúp tăng tính bảo mật và ổn định cho hệ thống.

Ngược lại, một luồng (thread) là một tiến trình con nhẹ trong một chương trình duy nhất, hoạt động trong cùng một không gian bộ nhớ. Điều này giúp việc chia sẻ dữ liệu giữa các luồng trở nên dễ dàng hơn so với giữa các quy trình. Nhờ tiêu tốn ít tài nguyên hơn, luồng trở thành lựa chọn hiệu quả khi xử lý các tác vụ nhỏ mà không cần tạo quy trình mới.

Các quy trình trong Python
Các quy trình trong Python

Mỗi quy trình luôn bắt đầu với một luồng chính (main thread). Khi cần thiết, bạn có thể tạo thêm các luồng mới để thực hiện các tác vụ song song, sau đó hợp nhất kết quả với luồng chính khi hoàn thành. Cách hoạt động này giúp tối ưu hóa thời gian xử lý, đặc biệt hữu ích trong các ứng dụng yêu cầu hiệu suất cao như hệ thống máy chủ web hoặc nền tảng lưu trữ dữ liệu.

Luồng có các đặc điểm quan trọng như:

  • Có điểm bắt đầu, trình tự thực thi và điểm kết thúc.
  • Luôn có một con trỏ lệnh để theo dõi tiến trình thực thi.
  • Có thể bị gián đoạn tạm thời (pre-empted) hoặc tạm dừng để nhường tài nguyên cho luồng khác (yielding), giúp hệ thống hoạt động mượt mà hơn.

Các module xử lý luồng trong Python

Python cung cấp hai module chính để quản lý luồng: _threadthreading. Mỗi module có những đặc điểm riêng, giúp lập trình viên kiểm soát và tối ưu hóa việc thực thi đa luồng trong ứng dụng:

1. Module _thread

_thread là module cấp thấp, xuất hiện từ những phiên bản đầu tiên của Python. Nó cung cấp API cơ bản để quản lý luồng, giúp các luồng chạy đồng thời trong cùng một không gian dữ liệu toàn cục. Module này cũng hỗ trợ các cơ chế khóa đơn giản (mutex) để đồng bộ hóa luồng, ngăn chặn xung đột dữ liệu.

multithreading python 21
Xử lý đa luồng trong Python

2. Module threading

Được giới thiệu từ Python 2.4, threading là phiên bản nâng cấp của _thread, cung cấp một API toàn diện hơn giúp lập trình viên quản lý luồng dễ dàng hơn. Module threading không chỉ kế thừa tất cả các phương thức của _thread, mà còn bổ sung nhiều tính năng mạnh mẽ:

  • threading.activeCount() – Trả về số lượng luồng đang hoạt động.
  • threading.currentThread() – Trả về luồng hiện tại.
  • threading.enumerate() – Trả về danh sách các luồng đang chạy.

Ngoài ra, threading còn cung cấp lớp Thread, hỗ trợ quản lý và thao tác trên luồng một cách linh hoạt:

  • run() – Điểm bắt đầu của luồng.
  • start() – Bắt đầu thực thi luồng.
  • join([time]) – Đợi luồng kết thúc.
  • isAlive() – Kiểm tra xem luồng có đang chạy không.
  • getName() / setName() – Lấy hoặc đặt tên cho luồng.

Việc hiểu rõ và áp dụng linh hoạt hai module này giúp lập trình viên tối ưu hóa hiệu suất của ứng dụng. Điều này đặc biệt quan trọng đối với các hệ thống yêu cầu xử lý đồng thời nhiều tác vụ như quản lý truy cập dữ liệu trên website hay tối ưu hóa tài nguyên hệ thống.

Cách tạo luồng mới trong Python

Để tạo và khởi chạy một luồng mới trong Python, bạn có thể sử dụng module cấp thấp _thread hoặc module cấp cao hơn threading. Trong đó, threading được khuyến nghị do cung cấp nhiều tính năng mở rộng và dễ sử dụng hơn. Dưới đây là hướng dẫn sử dụng cả hai phương pháp:

1. Sử dụng module _thread

Module _thread cung cấp phương thức start_new_thread(), cho phép khởi tạo luồng một cách nhanh chóng và hiệu quả trên cả hệ điều hành LinuxWindows. Cú pháp như sau:

_thread.start_new_thread(function, args[, kwargs])

Lệnh này sẽ ngay lập tức khởi chạy luồng mới và thực thi hàm được chỉ định với các đối số tương ứng. Khi hàm hoàn tất, luồng sẽ tự động kết thúc. Đoạn code sau minh họa cách sử dụng _thread để tạo và chạy nhiều luồng song song:

import _thread
import time
def process_task(task_name, *args):
    print(f"Đang xử lý: {task_name}", *args)
# Khởi tạo luồng mới
_thread.start_new_thread(process_task, ("Kiểm tra hiệu suất server Vietnix", 1))
_thread.start_new_thread(process_task, ("Tối ưu băng thông hosting", 2, 3))
# Chờ các luồng hoàn tất trước khi kết thúc chương trình
time.sleep(0.5)
  • Kết quả như sau:

Đang xử lý: Kiểm tra hiệu suất server Vietnix 1
Đang xử lý: Tối ưu băng thông hosting 2 3

Mặc dù module _thread có thể xử lý đa luồng ở mức thấp, nhưng nó thiếu các tính năng quản lý luồng nâng cao. Vì vậy, threading thường được sử dụng nhiều hơn.

2. Sử dụng module threading để tạo luồng

Module threading cung cấp lớp Thread, giúp quản lý luồng một cách dễ dàng và linh hoạt hơn. Các bước thực hiện:

  • Tạo một hàm chứa logic mà luồng sẽ thực thi.
  • Khởi tạo một đối tượng Thread và truyền vào hàm cần chạy.
  • Gọi phương thức start() để chạy luồng.
  • (Tuỳ chọn) Sử dụng join() để đợi luồng hoàn thành trước khi tiếp tục chương trình.

Ví dụ:

import threading
import time
def process_task(task_name, *args):
    print(f"Đang xử lý: {task_name}", *args)
# Tạo và khởi chạy luồng
thread1 = threading.Thread(target=process_task, args=("Quét bảo mật website", 1))
thread2 = threading.Thread(target=process_task, args=("Giám sát uptime server", 2, 3))
thread1.start()
thread2.start()
# Chờ các luồng hoàn tất
thread1.join()
thread2.join()
print("Tất cả tác vụ đã hoàn thành.")
  • Kết quả như sau:

Đang xử lý: Quét bảo mật website 1
Đang xử lý: Giám sát uptime server 2 3
Tất cả tác vụ đã hoàn thành.

Đồng bộ hóa các luồng trong Python

Khi làm việc với đa luồng trong Python, việc đồng bộ hóa giữa các luồng là rất quan trọng để tránh xung đột dữ liệu và đảm bảo chương trình hoạt động chính xác. Python cung cấp module threading, trong đó có cơ chế khóa đơn giản giúp bạn kiểm soát thứ tự thực thi của các luồng. Để đồng bộ hóa luồng, Python sử dụng Lock(), tạo ra một đối tượng khóa. Khi một luồng muốn thực thi một đoạn mã quan trọng, nó sẽ gọi phương thức acquire(blocking) để chiếm quyền truy cập:

  • Nếu blocking được đặt là 1, luồng sẽ chờ cho đến khi khóa được giải phóng.
  • Nếu blocking0, luồng sẽ kiểm tra trạng thái khóa và tiếp tục ngay nếu không chiếm được khóa.

Sau khi hoàn thành công việc, luồng sẽ gọi release() để giải phóng khóa, cho phép các luồng khác tiếp tục thực thi. Nhiều luồng có thể truy cập và cập nhật thông tin cùng lúc, do đó cần sử dụng Lock để tránh xung đột dữ liệu:

import threading
import time
# Tạo một đối tượng khóa
server_status_lock = threading.Lock()
# Giả lập danh sách máy chủ với trạng thái
server_status = {
    "Server-1": "Đang hoạt động",
    "Server-2": "Đang hoạt động",
    "Server-3": "Đang hoạt động"
}
def check_server_status(server_name):
    """Hàm kiểm tra trạng thái máy chủ, có sử dụng lock để đồng bộ."""
    print(f"{server_name} - Bắt đầu kiểm tra...")
    # Sử dụng Lock để đảm bảo chỉ một luồng có thể cập nhật trạng thái tại một thời điểm
    with server_status_lock:
        print(f"{server_name} - Đang lấy trạng thái...")
        time.sleep(2)  # Giả lập thời gian xử lý
        server_status[server_name] = "Đã kiểm tra"
        print(f"{server_name} - Trạng thái cập nhật: {server_status[server_name]}")
# Tạo danh sách luồng
threads = []
for server in server_status.keys():
    thread = threading.Thread(target=check_server_status, args=(server,))
    threads.append(thread)
    thread.start()
# Chờ tất cả luồng hoàn thành
for thread in threads:
    thread.join()
print("Hoàn tất kiểm tra tất cả máy chủ!")

Giải thích:

  • Sử dụng server_status_lock để đảm bảo chỉ một luồng cập nhật trạng thái máy chủ tại một thời điểm.
  • Dùng with server_status_lock: thay vì acquire()release() để tránh lỗi quên giải phóng khóa.
  • Mô phỏng độ trễ với time.sleep(2), giúp kiểm tra xem nếu không có khóa, trạng thái có thể bị ghi đè không mong muốn.

Chương trình trên sẽ lần lượt kiểm tra từng máy chủ và cập nhật trạng thái mà không bị xung đột giữa các luồng. Điều này đảm bảo rằng hệ thống lưu trữ hoạt động ổn định ngay cả khi nhiều tiến trình chạy đồng thời.

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

Trong lập trình đa luồng, việc quản lý dữ liệu giữa các luồng là một thách thức quan trọng. Python cung cấp module Queue giúp quản lý hàng đợi một cách hiệu quả, đảm bảo dữ liệu được xử lý theo thứ tự ưu tiên mà không xảy ra xung đột giữa các luồng. Các phương thức chính trong module Queue:

  • get() – Lấy và xóa một phần tử khỏi hàng đợi.
  • put() – Thêm phần tử vào hàng đợi.
  • qsize() – Trả về số lượng phần tử hiện có trong hàng đợi.
  • empty() – Kiểm tra xem hàng đợi có rỗng không.
  • full() – Kiểm tra xem hàng đợi có đầy không.

Dưới đây là cách tạo và quản lý hàng đợi trong môi trường đa luồng:

import queue
import threading
import time
class WorkerThread(threading.Thread):
    def __init__(self, thread_id, task_queue):
        threading.Thread.__init__(self)
        self.thread_id = thread_id
        self.task_queue = task_queue
    def run(self):
        while True:
            try:
                task = self.task_queue.get(timeout=3)  # Lấy công việc từ hàng đợi
                print(f"Thread-{self.thread_id} đang xử lý: {task}")
                time.sleep(2)  # Giả lập thời gian xử lý
                self.task_queue.task_done()  # Đánh dấu hoàn thành công việc
            except queue.Empty:
                break
# Tạo hàng đợi và danh sách công việc
task_queue = queue.Queue()
tasks = ["Tối ưu tốc độ website", "Cấu hình bảo mật", "Cập nhật cơ sở dữ liệu", "Quản lý tài nguyên"]
# Đưa các công việc vào hàng đợi
for task in tasks:
    task_queue.put(task)
# Khởi tạo và chạy các luồng xử lý
threads = []
for i in range(3):  # Sử dụng 3 luồng để xử lý công việc
    thread = WorkerThread(i, task_queue)
    thread.start()
    threads.append(thread)
# Đợi tất cả các luồng hoàn thành
for thread in threads:
    thread.join()
print("Tất cả công việc đã được xử lý.")

Lợi ích khi sử dụng hàng đợi ưu tiên:

  • Tối ưu hiệu suất – Phân chia công việc hợp lý giúp sử dụng tài nguyên máy chủ hiệu quả hơn.
  • Tránh xung đột dữ liệu – Hàng đợi đảm bảo mỗi công việc chỉ được xử lý bởi một luồng duy nhất.
  • Dễ dàng mở rộng – Có thể điều chỉnh số lượng luồng để phù hợp với khối lượng công việc.

Vietnix – Nhà cung cấp dịch vụ lưu trữ tốc độ cao

Vietnix là một trong những đơn vị hàng đầu tại Việt Nam trong lĩnh vực web hostingVPSthuê máy chủ và domain, mang đến giải pháp lưu trữ tối ưu với hiệu suất cao và bảo mật vượt trội. Với hạ tầng mạnh mẽ cùng đội ngũ kỹ thuật hỗ trợ 24/7, Vietnix cam kết đảm bảo tốc độ truy cập nhanh, ổn định, giúp website của bạn hoạt động mượt mà. Hơn 80.000 khách hàng đã tin tưởng sử dụng dịch vụ của Vietnix để tối ưu hiệu suất website và bảo vệ dữ liệu quan trọng. Liên hệ ngay để được tư vấn dịch vụ phù hợp!

Thông tin liên hệ:

  • Hotline: 18001093
  • Email: sales@vietnix.com.vn 
  • Địa chỉ: 265 Hồng Lạc, Phường 10, Quận Tân Bình, Thành Phố Hồ Chí Minh.
  • Website: https://vietnix.vn/

Câu hỏi thường gặp

Làm thế nào để đo lường hiệu suất của một chương trình sử dụng đa luồng?

Để đo lường hiệu suất của một chương trình đa luồng trong Python, có thể sử dụng các phương pháp sau:
Thời gian thực thi: Dùng time.perf_counter() để đo thời gian chạy tổng thể.
Sử dụng cProfile: Dùng cProfile.run() để phân tích chi tiết thời gian thực thi của từng hàm.
Theo dõi CPU và bộ nhớ: Dùng psutil để kiểm tra mức sử dụng CPU và RAM theo từng luồng.
Threading Performance Metrics: Dùng threading.active_count() hoặc threading.enumerate() để theo dõi số luồng đang hoạt động.

Cách đảm bảo dữ liệu được chia sẻ an toàn giữa các luồng mà không gây deadlock?

Để chia sẻ dữ liệu an toàn giữa các luồng mà không gây deadlock, có thể sử dụng:
Lock và RLock: Tránh giữ nhiều khóa cùng lúc, luôn tuân theo thứ tự nhất quán khi khóa.
Queue: Dùng queue.Queue() để truyền dữ liệu giữa các luồng mà không cần khóa.
Condition và Event: Đồng bộ luồng bằng tín hiệu thay vì khóa cứng tài nguyên.
Atomic Operations: Dùng threading.local() hoặc collections.deque() với maxlen để giảm thiểu xung đột.

Python có hỗ trợ ưu tiên luồng hay kiểm soát thứ tự thực thi của luồng không?

Python không hỗ trợ gán mức độ ưu tiên cho luồng, vì trình lập lịch của hệ điều hành quyết định thứ tự thực thi. Tuy nhiên, có thể kiểm soát phần nào bằng threading.Lock(), queue.PriorityQueue(), hoặc time.sleep(). Nếu cần kiểm soát chặt chẽ, nên cân nhắc sử dụng multiprocessing.

Có nên sử dụng multiprocessing thay vì threading khi làm việc với Python và khi nào?

Câu trả lời phụ thuộc vào loại tác vụ mà bạn đang xử lý:
Sử dụng threading nếu công việc chủ yếu là I/O-bound (tức là chờ đợi phản hồi từ mạng, đọc/ghi file, xử lý database, gọi API…). Vì Global Interpreter Lock (GIL) của Python không ảnh hưởng nhiều đến các tác vụ I/O, nên các luồng (threads) có thể thay phiên nhau chạy mà không bị tắc nghẽn CPU.
Sử dụng multiprocessing nếu công việc chủ yếu là CPU-bound (tức là cần xử lý dữ liệu nặng như tính toán số học, machine learning, mã hóa/giải mã dữ liệu…). Do GIL ngăn chặn nhiều luồng chạy song song trên CPU, nên threading sẽ không mang lại hiệu suất cao. Thay vào đó, multiprocessing sẽ tạo ra nhiều tiến trình (process) riêng biệt, mỗi tiến trình có bộ nhớ và CPU riêng, giúp tận dụng đa nhân CPU tốt hơn.

Lời kết

Đa luồng trong Python là một kỹ thuật giúp tối ưu hiệu suất của chương trình khi xử lý nhiều tác vụ đồng thời. Dù có những hạn chế do GIL, nhưng khi được sử dụng đúng cách, nó vẫn mang lại lợi ích đáng kể, đặc biệt trong các tác vụ I/O. Hy vọng qua bài viết này, bạn đã nắm rõ cách hoạt động, cách triển khai cũng như những lưu ý quan trọng khi làm việc với đa luồng trong Python. Nếu có bất kỳ thắc mắc nào, hãy để lại bình luận ngay bên dưới, mình sẽ giải đáp nhanh nhất!

Mọi người cũng xem:

Cao Lê Viết Tiến

PHP Leader
tại
Vietnix

Kết nối với mình qua

Icon Quote
Icon Quote

Học lập trình online cùng vietnix

Học lập trình online cùng Vietnix

PHPXem thêmThu gọn