← Lập trình Python nâng cao

Bài 14 · Nâng cao · 26 phút· Cập nhật 11/06/2026

Free-threading: Python không-GIL

Biên soạn bởi Nguyễn Anh Tuấn

PEP 703, bản build không-GIL: 3.13 thử nghiệm → 3.14 hỗ trợ chính thức (PEP 779); song song THẬT & những đánh đổi.

Bài GIL cho thấy CPU-bound + nhiều luồng = không nhanh hơn. Free-threading (PEP 703) bỏ GIL để luồng CPU-bound chạy song song thật trên nhiều lõi - mà vẫn chia sẻ bộ nhớ trong một tiến trình. Chỉnh widget để thấy khác biệt:

Cùng một việc CPU-bound chia cho 4 luồng - so sánh hai bản build:

luồng:
4 luồng CPU-bound chạy đồng thời?
▶ chạy
⏸ chờ
⏸ chờ
⏸ chờ

Có GIL → chỉ 1 luồng chạy bytecode; các luồng khác CHỜ tới lượt.

Tăng tốc CPU-bound ≈ 1.0× (wall 400ms) - build có GIL: thêm luồng KHÔNG nhanh hơn cho việc CPU-bound.
★ Python 3.14: free-threaded đã được HỖ TRỢ CHÍNH THỨC (PEP 779), không còn thử nghiệm như 3.13. Đánh đổi: code đơn luồng chậm hơn ~5–10%, và phải cẩn thận an toàn luồng hơn.

Điểm mấu chốt: CÙNG một đoạn code, hai bản build cho hai kết quả khác hẳn:

cpu_threads.py - chạy y nguyên trên cả hai bản

import time, threading

def nang(n):
    s = 0
    for i in range(n): s += i * i

def chay_4_luong():
    ts = [threading.Thread(target=nang, args=(20_000_000,)) for _ in range(4)]
    t = time.perf_counter()
    [x.start() for x in ts]; [x.join() for x in ts]
    return time.perf_counter() - t

print(round(chay_4_luong(), 2), "s")

Kết quả khi chạy

# python3.14   (co GIL):       ~3.4 s  -> 4 luong KHONG nhanh hon tuan tu
# python3.14t  (free-threaded): ~1.0 s  -> nhanh ~3-4x (song song that)
  • Bỏ GIL → luồng CPU-bound chạy song song thật trên nhiều lõi.
  • Khác đa tiến trình: vẫn chung bộ nhớ một tiến trình → KHÔNG cần pickle dữ liệu.
  • Cùng code: build có GIL ≈1× cho CPU-bound; free-threaded ≈ số lõi.

kiem_build.py

import sys, sysconfig
print(sys._is_gil_enabled())                          # True = co GIL; False = free-threaded
print(sysconfig.get_config_var("Py_GIL_DISABLED"))    # 0 = build chuan; 1 = free-threaded

Kết quả khi chạy

True
0

Cài & chạy bản free-threaded

Bộ cài python.org cho chọn tuỳ chọn free-threaded; interpreter thường có hậu tố t (vd python3.14t). Với uv: uv python install 3.14t rồi uv run --python 3.14t script.py. Đây là interpreter RIÊNG, đứng cạnh bản thường - không thay thế.
  • sys._is_gil_enabled(): False nghĩa là đang chạy không-GIL.
  • sysconfig Py_GIL_DISABLED = 1 → đây là build free-threaded.
  • Bản free-threaded có hậu tố t (python3.14t); cài qua python.org hoặc uv.
  • Python 3.13: free-threading ra mắt dạng THỬ NGHIỆM (bản build riêng).
  • Python 3.14: HỖ TRỢ CHÍNH THỨC (PEP 779) - cột mốc lớn của ngôn ngữ.
  • Build mặc định VẪN có GIL; free-threaded là một biến thể opt-in.
  • Từ 3.14, adaptive interpreter (bài GIL) đã bật cả ở chế độ free-threaded → đỡ chậm hơn trước.

Vì sao đây là chuyện lớn

GIL gắn với CPython gần 30 năm. Đưa free-threading thành "hỗ trợ chính thức" mở đường cho song song CPU THẬT bằng luồng - điều cộng đồng Python mong mỏi rất lâu. Nhưng "chính thức" không có nghĩa "mặc định" hay "mọi thư viện đã sẵn sàng".

Bỏ GIL không miễn phí - và nó phơi bày những lỗi GIL từng giấu:

  • Code ĐƠN luồng chậm hơn ~5-10%: đếm tham chiếu phải an toàn-luồng (không còn rẻ nhờ GIL).
  • Thư viện C/extension phải được cập nhật để chạy đúng ở chế độ không-GIL.
  • Race condition LỘ rõ: thứ "chạy được nhờ GIL che" ở bài trước sẽ SAI trên free-threaded.

Liên hệ bài trước: GIL từng che lỗi

Nhớ counter += 1 không khoá ở bài "Đa luồng": trên build có GIL nó thường vẫn ra đúng. Trên free-threaded, các luồng đua THẬT → nó gần như chắc chắn mất update. Free-threading cho song song thật, đổi lại bạn phải dùng Lock/Queue đúng - kỷ luật đồng bộ giờ là bắt buộc, không còn "may nhờ GIL".
Đa luồng (GIL)Đa tiến trìnhFree-threading
Song song CPU thậtKhông
Chia sẻ bộ nhớKhông (pickle)
Race conditionCó (GIL che bớt)Ít (cách ly)Có (lộ rõ → cần Lock)
Chi phí khởi tạoNhẹNặng + pickleNhẹ
Hợp nhất vớiI/O-boundCPU-boundCPU-bound + chia sẻ bộ nhớ
  • Phần lớn app: build chuẩn (có GIL) vẫn ổn - I/O-bound dùng threads/async; CPU-bound dùng đa tiến trình.
  • Cân nhắc free-threading khi cần song song CPU MÀ muốn chia sẻ bộ nhớ, và sẵn sàng lo an toàn luồng + kiểm thư viện.
  • Hệ sinh thái vẫn đang trưởng thành: thử có chủ đích, ĐO trước khi tin, kiểm thư viện C bạn dùng.

Hết mạch “chạy nhiều việc song song”

Bạn đã hiểu GIL, đa luồng/đa tiến trình, và free-threading. Còn một mô hình đồng thời rất khác: async/await - phục vụ HÀNG NGHÌN tác vụ I/O trên MỘT luồng mà không cần khoá. Đó là bài kế tiếp, trước khi tới capstone.

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

Là bản CPython BỎ GIL (PEP 703): nhiều luồng chạy bytecode SONG SONG THẬT trên nhiều lõi - kể cả việc CPU-bound. Khác đa tiến trình ở chỗ các luồng vẫn DÙNG CHUNG bộ nhớ trong một tiến trình (không phải pickle dữ liệu qua lại).

Ở 3.13 free-threading là THỬ NGHIỆM. Từ 3.14, nó được HỖ TRỢ CHÍNH THỨC (PEP 779) - cột mốc lớn. Nhưng đây vẫn là một BẢN BUILD RIÊNG (free-threaded); build mặc định VẪN có GIL. Specializing adaptive interpreter (bài GIL) cũng đã được bật ở chế độ free-threaded từ 3.14.

sys._is_gil_enabled() trả False nếu đang chạy không-GIL; sysconfig.get_config_var("Py_GIL_DISABLED") trả 1 nếu là build free-threaded. Bản free-threaded thường có hậu tố t (vd python3.14t).

Bộ cài chính thức từ python.org cho chọn tuỳ chọn "free-threaded". Với uv: uv python install 3.14t rồi uv run --python 3.14t script.py. Lưu ý đây là một interpreter RIÊNG cạnh bản thường.

Có. (1) Code ĐƠN LUỒNG chậm hơn ~5-10% (đếm tham chiếu phải an toàn-luồng, không còn rẻ nhờ GIL). (2) Nhiều thư viện C cần cập nhật để chạy đúng ở chế độ không-GIL. (3) AN TOÀN LUỒNG giờ là việc của BẠN: GIL từng vô tình che nhiều race; bỏ GIL thì chúng LỘ ra → phải dùng Lock/Queue cẩn thận.

Không hẳn - là một lựa chọn KHÁC. Free-threading: song song CPU mà CHIA SẺ bộ nhớ trong một tiến trình (đỡ pickle, đỡ nhân bản RAM) - nhưng phải tự lo an toàn luồng. Đa tiến trình: cách ly bộ nhớ (ít race) nhưng tốn pickle/RAM. Tuỳ bài toán; nhiều khi đa tiến trình vẫn đơn giản & an toàn hơn.

Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.

Tick những điều em tự tin làm được sau khi học bài này. 0/6

Trả lời vài câu để chắc rằng em đã nắm bài.

Câu 1/3 Điểm: 0

Free-threading (PEP 703) khác đa tiến trình ở điểm cốt lõi nào?

  1. 1

    GIL vs không-GIL

    Dùng widget Bước 1: CPU-bound 4 luồng, so tăng tốc giữa "build chuẩn" và "free-threaded". Vì sao khác?

    Hoàn thành khi: Build chuẩn ≈1× (GIL nối tiếp); free-threaded ≈4× (song song thật). Bạn giải thích đúng.

  2. 2

    Bạn đang chạy bản nào?

    Chạy import sys, sysconfig; in sys._is_gil_enabled()sysconfig.get_config_var("Py_GIL_DISABLED").

    Hoàn thành khi: Build chuẩn: True0. Nếu cài bản free-threaded: False1. Bạn biết mình đang dùng bản nào.

  3. 3

    Race giờ LỘ

    Lấy đoạn counter += 1 không khoá (bài trước). Bằng lời (hoặc nếu có bản free-threaded thì chạy): vì sao trên free-threaded nó gần như chắc chắn mất update?

    Hoàn thành khi: Không còn GIL serial hoá → các luồng thực sự đua đọc→ghi → mất update rõ. Phải dùng Lock/Queue.

  4. 4

    Cái giá đơn luồng

    Bằng lời: vì sao bản free-threaded chạy code ĐƠN luồng chậm hơn ~5-10%?

    Hoàn thành khi: Đếm tham chiếu giờ phải an toàn-luồng (đồng bộ hoá) thay vì rẻ như khi có GIL.

  5. 5

    Chọn công cụ

    Việc CPU-bound cần chia sẻ một cấu trúc dữ liệu lớn: free-threading hay multiprocessing? Nêu đánh đổi.

    Hoàn thành khi: Free-threading nếu muốn chia sẻ bộ nhớ (đỡ pickle/RAM) & chịu lo an toàn luồng; multiprocessing nếu muốn cách ly an toàn, chấp nhận pickle/RAM.