Thursday, February 12, 2026

Giải mã GIL trong Python: Tại sao Python không thể chạy đa nhân thực thụ?

GIL là gì?

GIL (Global Interpreter Lock) là một "chiếc khóa" quyền lực trong trình thông dịch CPython (phiên bản phổ biến nhất của Python). Nó chỉ cho phép duy nhất một thread kiểm soát trình thông dịch Python tại một thời điểm.

Nói cách khác, ngay cả khi bạn có một CPU 16 nhân, nhưng nếu bạn chạy một chương trình Python đa luồng (multithreading) để xử lý các tác vụ tính toán nặng, thì tại mỗi thời điểm chỉ có một nhân duy nhất hoạt động.

GIL (Global Interperter Lock) là cái gì và tại sao python lại dùng nó? 

 

Tại sao Python lại cần GIL?

Lịch sử phát triển của Python cho thấy GIL ra đời để giải quyết bài toán quản lý bộ nhớ:

  • Reference Counting: Python quản lý bộ nhớ bằng cách đếm số lượng tham chiếu đến một đối tượng. Nếu không có khóa, hai luồng có thể cùng lúc thay đổi con số này, dẫn đến rò rỉ bộ nhớ hoặc làm sụp đổ chương trình (race condition).

  • Đơn giản hóa: GIL giúp việc tích hợp các thư viện viết bằng C/C++ trở nên dễ dàng và an toàn hơn.

Ví dụ cụ thể: Sự "bất lực" của Multithreading với CPU-bound

Hãy cùng xem ví dụ khi ta thực hiện một phép tính lặp lại 50 triệu lần:

import time
from threading import Thread

COUNT = 50_000_000

def countdown(n):
    while n > 0:
        n -= 1

# Chạy đơn luồng (Single-thread)
start = time.time()
countdown(COUNT)
print(f"Đơn luồng: {time.time() - start:.2f} giây")

# Chạy đa luồng (Multi-thread)
t1 = Thread(target=countdown, args=(COUNT//2,))
t2 = Thread(target=countdown, args=(COUNT//2,))

start = time.time()
t1.start(); t2.start()
t1.join(); t2.join()
print(f"Đa luồng (2 threads): {time.time() - start:.2f} giây")

Kết quả bất ngờ: Bạn sẽ thấy thời gian chạy của 2 luồng thậm chí còn lâu hơn hoặc bằng 1 luồng. Đó là vì GIL bắt các luồng phải xếp hàng chờ đợi nhau để được dùng CPU.

Vậy Python có vô dụng với đa nhiệm?

Câu trả lời là KHÔNG. GIL chỉ ảnh hưởng đến các tác vụ CPU-bound (tính toán nặng như xử lý ảnh, video).

Đối với các tác vụ I/O-bound (như gọi API, truy vấn DynamoDB, hoặc đọc file), GIL sẽ được giải phóng khi luồng đang đợi phản hồi từ bên ngoài. Lúc này, Multithreading vẫn cực kỳ hiệu quả.

Giải pháp cho dân chuyên nghiệp

Nếu bạn đang xây dựng các hệ thống AI hay Data Engineering cần xử lý song song thực sự:

  1. Sử dụng Multiprocessing: Thay vì dùng threading, hãy dùng multiprocessing. Mỗi tiến trình sẽ có một trình thông dịch Python và một GIL riêng, giúp tận dụng tối đa đa nhân CPU.

  2. Viết Extension bằng C++: Bạn có thể đẩy các phần tính toán nặng xuống lớp C++, giải phóng GIL và thực hiện song song ở đó.

  3. Python 3.13+: Hiện nay cộng đồng Python đang nỗ lực loại bỏ GIL (no-GIL build), đây là thông tin rất đáng mong chờ cho tương lai.


Lời kết: Hiểu về GIL giúp chúng ta chọn đúng công cụ cho đúng việc. Nếu bạn làm App Web với FastAPI, đừng quá lo về GIL. Nhưng nếu bạn làm AI Training, hãy cân nhắc kỹ về cách phân bổ tiến trình nhé!

No comments:

Post a Comment