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:
Có GIL → chỉ 1 luồng chạy bytecode; các luồng khác CHỜ tới lượt.
Đ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
- ▸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
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
| Đa luồng (GIL) | Đa tiến trình | Free-threading | |
|---|---|---|---|
| Song song CPU thật | Không | Có | Có |
| Chia sẻ bộ nhớ | Có | Không (pickle) | Có |
| Race condition | Có (GIL che bớt) | Ít (cách ly) | Có (lộ rõ → cần Lock) |
| Chi phí khởi tạo | Nhẹ | Nặng + pickle | Nhẹ |
| Hợp nhất với | I/O-bound | CPU-bound | CPU-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”
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.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Free-threading (PEP 703) khác đa tiến trình ở điểm cốt lõi nào?
- 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
Bạn đang chạy bản nào?
Chạy
import sys, sysconfig; insys._is_gil_enabled()vàsysconfig.get_config_var("Py_GIL_DISABLED").Hoàn thành khi: Build chuẩn:
Truevà0. Nếu cài bản free-threaded:Falsevà1. Bạn biết mình đang dùng bản nào. - 3
Race giờ LỘ
Lấy đoạn
counter += 1khô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
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
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;
multiprocessingnếu muốn cách ly an toàn, chấp nhận pickle/RAM.