Tiến độ phát triển No-GIL CPython
(lwn.net)- Python steering council đã bày tỏ ý định phê duyệt PEP 703, vốn biến GIL thành tùy chọn qua nhiều bản phát hành, và các điều kiện cuối cùng vẫn đang được điều chỉnh
- Bản dựng
--disable-gilcủa CPython 3.13 sẽ được chuẩn bị ở dạng thử nghiệm, trong đó stable ABI và khả năng tương thích wheel của module mở rộng nổi lên như vấn đề kỹ thuật lớn nhất - Các wheel
abi3hiện có có thể không khớp nguyên trạng với no-GIL CPython 3.13, nên việc đưa vàoabi4, thay đổi limited C API và chuyển macro đếm tham chiếu thành lời gọi hàm đang được thảo luận - Có lo ngại rằng
pipcó thể chọn nhầm wheel cho bản dựng GIL và no-GIL; việc cài đặt sai trong im lặng nguy hiểm hơn lỗi cài đặt đơn thuần - Tên bản dựng no-GIL được đề xuất là free-threading thay vì
nogil, nhưng cần giải quyết cùng lúc cả tên file thực thi, shebang, cài đặt song song và đóng gói cho các bản phân phối
PEP 703 và vị thế hiện tại của no-GIL CPython
- Python steering council đã bày tỏ ý định phê duyệt PEP 703 vào cuối tháng 7; PEP này có nội dung biến Global Interpreter Lock (GIL) trong CPython thành tùy chọn
- Các điều kiện phê duyệt chi tiết vẫn chưa được chốt, nhưng thảo luận triển khai liên quan và việc chuẩn bị của hệ sinh thái đã diễn ra
- Về dài hạn, hướng đi được giả định là tiến tới một phiên bản CPython duy nhất không có GIL, nhưng trước mắt đây là giai đoạn thử nghiệm hành vi no-GIL trên interpreter được build với tùy chọn
--disable-gil - CPython 3.13 dự kiến vào tháng 10 năm 2024, và bản dựng no-GIL của phiên bản này mang tính thử nghiệm
stable ABI và khả năng tương thích của module mở rộng
- Sam Gross đã bàn trên Python discussion forum về cách PEP 703 ăn khớp với stable ABI của CPython
- stable ABI nhằm cho phép module mở rộng hoạt động bằng cùng một binary wheel trên nhiều phiên bản CPython, để không cần build lại cho mỗi bản phát hành CPython mới
- Extension được build cho stable ABI có thể không hoạt động nguyên trạng trên bản dựng no-GIL của CPython 3.13
- Để giải quyết điều này, một số bổ sung và thay đổi cho limited C API đã được đề xuất
- Extension chỉ dùng limited C API có thể tạo binary sử dụng stable ABI
- Các thay đổi được đề xuất bao gồm kế hoạch hiện có là chuyển một số macro tăng/giảm reference count của object thành lời gọi hàm
- Mục tiêu là cho phép có binary extension hoạt động trên cả bản dựng GIL lẫn no-GIL
abi3, abi4 và vấn đề chọn wheel
- Victor Stinner cho rằng để thử nghiệm no-GIL thành công, cần có một giải pháp đơn giản cho các extension hoạt động trên cả hai loại interpreter
- Vì extension được build cho stable ABI trên CPython 3.12 trở xuống không tương thích với bản dựng no-GIL từ 3.13 trở đi, phương án tạo một phiên bản ABI mới là abi4 đã được đưa ra
- stable ABI hiện tại là
abi3 - Số ABI và số phiên bản major của CPython không nhất thiết phải gắn với nhau
- stable ABI hiện tại là
- Gross cho rằng các extension muốn hỗ trợ no-GIL có thể chấp nhận phần nào gánh nặng tạo hai binary wheel
- Ông lo ngại hơn về tình huống dự án no-GIL bị ràng buộc quá mức vào các cải tiến C API và stable ABI
- Alex Gaynor cũng có nhiều package wheel
abi3, nhưng cho rằng việc tạo hai wheel một lần không phải gánh nặng quá lớn- Tuy nhiên, việc
piphiện tại và trong tương lai có chọn đúng wheel hay không là điều quan trọng
- Tuy nhiên, việc
- Brett Cannon cho rằng logic hiện tại của
pipkhông phân biệt được hai phiên bản, nên nếu không có thay đổi nhưabi4,piphiện tại và cũ sẽ không hoạt động đúng
Lo ngại về việc pip hoạt động sai trong im lặng
- Gross cho rằng không cần quá lo về hỗ trợ
pipcũ trong bản dựng--disable-gilthử nghiệm của CPython 3.13- Lý do là việc
pipcũ bị hỏng trên phiên bản Python mới là chuyện phổ biến - Ví dụ được nêu là
pip==23.1.1trở xuống bị hỏng trên CPython 3.13 do thiếupkgutil.ImpImporter
- Lý do là việc
- Paul Moore, maintainer của
pip, cho rằng hỏng một cách rõ ràng và âm thầm cài sai package là hai vấn đề khác nhau- Có những người dùng vẫn sử dụng
pipcũ - Lỗi thất bại rõ ràng và lỗi âm thầm có tác động khác nhau tới người dùng
- Có những người dùng vẫn sử dụng
- Moore lo ngại rằng người dùng muốn thử bản dựng no-GIL hoặc free-threaded có thể nản lòng nếu phải debug vấn đề tương thích ABI
- Gaynor cũng cho rằng nếu
pipâm thầm hoạt động sai với các package bị ảnh hưởng, số lượng issue có thể đổ về rất nhiều
Cài đặt song song và tên file thực thi
- Barry Warsaw hỏi liệu có kế hoạch cài đặt chung bản dựng GIL và no-GIL trên cùng một hệ thống hay không
- Gross trả lời rằng tình huống này giống như cài các phiên bản Python khác nhau
- Cannon cho rằng phương án đưa hai binary vào một “fat” wheel cũng khả thi
- Tuy nhiên, tên binary bên trong wheel phải khác nhau
- Thảo luận về tên file thực thi tiếp tục ở một thread riêng
- Paul Moore cho rằng người dùng cần có thể dễ dàng thử chế độ no-GIL và dễ dàng chọn một trong hai chế độ GIL/no-GIL
- Nếu quá trình này khó trên Windows, macOS, Linux, v.v., điều đó có thể ảnh hưởng tiêu cực đến dự án no-GIL
- Người dùng phải dễ thử thì nhu cầu về bản dựng no-GIL mới xuất hiện, và áp lực lên maintainer package trong việc cung cấp wheel tương thích no-GIL cũng sẽ hình thành
Tranh luận tên gọi nogil và free-threading
- Barry Scott cho rằng tên file thực thi là quan trọng vì dòng shebang cần thể hiện interpreter nào sẽ được gọi
- Ông đưa ra các ví dụ như
python-nogil3,python-nogil3.13
- Ông đưa ra các ví dụ như
- Gregory P. Smith đưa ra ý kiến cá nhân rằng vì bản dựng no-GIL của CPython 3.13 là tính năng thử nghiệm, các bản phân phối không nên đưa nó vào
$PATHmặc định- Ông cũng cho rằng việc tên file thực thi dài còn lại trong shebang và kéo dài lâu dài là điều không mong muốn
- Ông đề xuất hoãn quyết định tên cài đặt sang sau 3.14
- Nhà phát triển Fedora Petr Viktorin chỉ ra rằng các bản phân phối nhiều khả năng sẽ muốn đóng gói interpreter no-GIL để người dùng thử nghiệm
- Moore cho rằng ông muốn chỉ định bản dựng free-threaded theo dạng như
#!/usr/bin/env python3.13-nogil- Đây là yêu cầu nhằm tránh hard-code một đường dẫn dài và không trực quan
- Trong thread liên quan đến trình cài đặt Windows do Steve Dower khởi xướng, Smith cho biết steering council muốn tránh tên
nogil- Lý do là tên này không truyền đạt tốt với phần lớn nhà phát triển non-core, họ không cần biết GIL là gì, và nó bao gồm cách diễn đạt phủ định
- Thuật ngữ free-threading được đề xuất làm phương án thay thế
- Gross cho rằng
free-threadingcũng không dễ hiểu với người ngoài và không phải thuật ngữ được dùng rộng rãi - Trong thảo luận thực tế, xu hướng thích tên ngắn rất mạnh, và xét khía cạnh đó
nogillà ứng viên mạnh nhất - Thay đổi cụ thể đã được phản ánh là đổi ABI tag của bản dựng no-GIL từ
nthànhttnghĩa là threading
Đề xuất abi4 và các việc còn lại
- Gross và Viktorin đã thảo luận các điểm vấn đề trong đề xuất thay đổi API, và phản hồi đó dẫn tới đề xuất ABI mới là abi4
- Gross đã tạo prototype cho ABI mới
- Viktorin nhìn chung đồng ý với cách tiếp cận, nhưng cho rằng các chi tiết cần được sắp xếp thêm
- Stinner cho rằng cần có PEP cho abi4, còn Viktorin xem đây là thảo luận pre-PEP
- Có sự nhầm lẫn về bảo đảm tương thích mà tổ hợp phiên bản limited C API và
abi3cung cấp, và phần này cũng ảnh hưởng tới hướng đi củaabi4 - Các khảo sát liên quan vẫn đang tiếp tục, và có khả năng sẽ có thảo luận trực tiếp tại core developer sprint vào giữa tháng 10
Câu chữ phê duyệt cuối cùng và tác động dài hạn
- Công việc về no-GIL hoặc free-threaded CPython vẫn đang tiếp diễn, nhưng phê duyệt cuối cùng cho PEP 703 vẫn đang chờ
- Dù độ trễ đã hơi kéo dài, PEP 703 và các tác động lan tỏa của nó có khả năng ảnh hưởng lớn đến phát triển CPython và hệ sinh thái trong hơn 5 năm tới
- steering council đang cố làm rõ tiêu chí phê duyệt
- Thomas Wouters cho biết ông đang tinh chỉnh câu chữ phê duyệt chính xác và muốn làm rõ nhiều quyết định
- Một số công việc cũng có thể được tiến hành tại core developer sprint
1 bình luận
Các ý kiến trên Hacker News
Nhìn vào máy tính hiện đại, tôi nghĩ tính song song tường minh có thể trở thành một yếu tố nền tảng hơn của khoa học máy tính so với mức đang thịnh hành trong sách giáo khoa
Có lẽ giờ đã đến giai đoạn chúng ta luôn phải viết mã song song một cách tường minh
Ví dụ, vòng lặp
forđang được thay thế bằng các phép toán nhưforeach,map,filter. Những biểu thức như vậy cho compiler/interpreter biết ý định rằng ta muốn áp dụng một thao tác nào đó lên mọi phần tử của cấu trúc dữ liệu, còn có song song hóa hay không và bằng cách nào thì giao cho compiler/runtimeTrong vận hành dịch vụ web, từng request riêng lẻ đủ nhanh, và lợi ích thực sự của tính song song nằm ở việc xử lý nhiều request cạnh nhau. No-GIL phù hợp với chỗ này
Nếu trong một request đơn lẻ có nhiều request con thì thường xử lý bằng mã bất đồng bộ, nhưng nhiều khi đó là vì tạo thread tốn kém hoặc thread pool phiền phức, hơn là vì lợi ích hiệu năng của bất đồng bộ. Bất đồng bộ tốt cho throughput nhưng xấu cho latency, và nếu song song hóa request của dịch vụ thì thường người ta lo latency nhiều hơn. Bất đồng bộ thắng chủ yếu vì tính dễ dùng
Một dạng song song khác xuất hiện trong các tác vụ offline quy mô lớn. Đó là những thứ như MapReduce hay Presto, và nhìn chung trông giống bài toán chia để trị. Huấn luyện mô hình trên GPU cũng tương tự như vậy
Điều đã không xảy ra là các thuật toán cục bộ có mức song song rất cao. Trong dịch vụ web, kích thước dữ liệu nhỏ nên lợi ích về latency ít, triển khai phức tạp, và chi phí phối hợp giữa các thread tăng lên. Ngoại lệ nhỏ là các thuật toán vector hóa, nhưng chúng chạy trên một core nên không có overhead phối hợp, và suy luận online cũng lại được vector hóa rất mạnh
Theo thời gian, cả hai đều đang tốt lên. Cũng như ngày càng nhiều ngôn ngữ và thư viện mặc định đã an toàn hơn, giờ ngày càng nhiều thứ mặc định đã có tính song song. Vẫn còn đường dài, nhưng tôi thấy may là chúng ta đã không làm quá sớm. Vì trong 10 năm qua, công nghệ đã tốt hơn rất nhiều
Ví dụ có thể so sánh những gì có thể làm an toàn với Rayon của Rust với những gì trước đây làm không an toàn bằng OpenMP của C++
Xa hơn nữa là những thứ tôi đang làm: https://legion.stanford.edu/, https://regent-lang.org/, https://github.com/nv-legate/cunumeric
Vì đó là chi tiết triển khai, nếu có thể trừu tượng hóa để dùng dễ hơn thì nên làm vậy
Để so sánh, mutex khoảng 25 nano giây và sẽ tăng thêm nếu có tranh chấp, nhưng mutex là đồng bộ hóa điểm-điểm
Điểm hay của Disruptor là nhiều thread có thể nhận cùng một message mà không cần nhiều công sức bổ sung
https://github.com/LMAX-Exchange/disruptor/wiki/Performance-...
https://gist.github.com/rmacy/2879257
Tôi mơ về một ngôn ngữ tương tự Smalltalk nhưng vẫn giữ đơn luồng cho đến khi song song hóa thật sự có ý nghĩa
Tôi đang tìm các bài toán song song không phải big data. Tính song song giống việc cho thêm xe lên đường hơn là tăng tốc chiếc xe. Nhưng tôi vẫn đang tìm xem người dùng desktop hay mobile cần làm việc gì cục bộ để tận dụng sức mạnh toán học của máy tính
Về ý tưởng song song, tôi cũng đang nghĩ đến Itanium và kiến trúc VLIW
Dùng
-nglà được. Nghĩa là no-gil hoặc next-generationCó khi là cờ compiler mới, cờ linker mới, link thư viện khác, thậm chí dùng lệnh compiler hoàn toàn khác. AIX đặc biệt như vậy
Vấn đề shebang có lẽ nên dựa vào quy ước Python hiện có:
from __future__ import nogilĐến thời điểm đó thì hot-swap interpreter là được
from __future__ importkhông phải là câu lệnh runtime mà là câu lệnh đặc biệt biểu thị flaghttps://docs.python.org/3/reference/simple_stmts.html#future...
future statement là theo từng module, còn GIL/no-GIL không dễ khớp với mô hình đó
Mỗi lần thấy đề xuất này, tôi lại thắc mắc làm sao bảo đảm chương trình vẫn hoạt động đúng. Một phần đáng kể code Python đa luồng hiện có được viết không an toàn
Vấn đề đặc biệt là data race mà tôi đã thấy lặp đi lặp lại trong codebase của nhiều công ty và các dự án mã nguồn mở. Những chương trình này không bị vỡ chỉ vì chúng ngầm dựa vào việc GIL chỉ cho phép một luồng thực thi tại một thời điểm
Nếu GIL biến mất, những chương trình này sẽ hỏng. Python là ngôn ngữ kiểu động, nên tôi rất nghi ngờ liệu có tồn tại một bộ phân tích tĩnh nào có thể tìm ra các vấn đề như vậy trong các chương trình Python hiện có hay không
Khả năng cao hơn là các bug tinh vi xuất hiện không xác định tại runtime. Nếu crash thì còn tốt, nhưng loại bug này nhiều khả năng dẫn đến việc thực hiện hành vi sai
Có lẽ đề xuất không có GIL này không nhằm dùng cho đa số chương trình. Nó có thể là một công cụ siêu chuyên biệt cho một số rất ít tình huống, nơi lập trình viên biết rằng không có GIL và viết code phù hợp với điều đó
GIL chỉ có nghĩa là tại một thời điểm chỉ một luồng có thể thực thi bytecode Python. Ngay cả interpreter có GIL cũng có thể chuyển luồng giữa các bytecode, và nhiều thao tác Python cần nhiều bytecode. Điều này bao gồm cả các phương thức built-in của các kiểu built-in mà nhiều người nghĩ là “atomic”
Vì vậy Python hiện vẫn cung cấp những thứ như lock, mutex, semaphore dù có GIL
Các luồng tranh giành GIL vốn đã có thể giật GIL của nhau vào thời điểm không hay và tạo ra hỗn loạn
Nếu chương trình chỉ chạy không GIL khi mọi dependency đều cho phép, thì sẽ có đủ thời gian để sửa các bug như vậy
Vậy thì việc xử lý vấn đề này trên quy mô lớn có lẽ sẽ diễn ra gần năm 2030. Tôi cũng không thấy nhiều production nâng runtime đang dùng lên bản phát hành mới nhất ngay lập tức
Tôi không muốn nghe có vẻ khắc nghiệt, nhưng Steering Council đã nói họ không muốn một cuộc migration từ 2 sang 3 nữa, nên mọi người sẽ không cập nhật một cách nhẹ nhàng đâu. Phần lớn nội dung hiện có trên mạng có thể nguy hiểm nếu copy-paste
Trong code Python thực tế có rất nhiều bug threading
OCaml chẳng phải cũng đã trải qua một quá trình tiến hóa tương tự sao? Tôi tò mò liệu có điểm nào có thể so sánh giữa hai dự án không
Vì vậy API thread hiện có tạo thread bên trong domain hiện tại và có thể cô lập code vốn kỳ vọng rằng lock được giữ. Code mới thay vào đó có thể tạo một domain mới bắt đầu với một thread. Cũng có thể cố ý dùng cả hai cùng nhau như một hình thức scheduling
Python đang cố biến lock thành hoàn toàn tùy chọn ở cấp toàn cục, nằm ngoài quyền kiểm soát của tác giả thư viện. Tuy nhiên lock của Python dường như chỉ được bảo đảm là bảo vệ chính runtime, nên phần lớn code dựa vào lock đó dù sao cũng có khả năng có bug, và vì thế kế hoạch của Python cũng có vẻ khả thi
Nếu có điểm chung thì có lẽ chỉ là phải tìm và sửa shared state ngoài dự kiến trong toàn bộ codebase runtime, cũng như sửa đổi C ABI
Giờ Python cũng có cơ hội bắt kịp Tcl về hiệu năng đa luồng: https://www.hammerdb.com/blog/uncategorized/why-tcl-is-700-f...
Thà port code Python sang Mojo để có đa luồng, SIMD và các cải thiện tốc độ khác còn hơn
Không muốn chuyển code Python sang nogil Python ư? Vậy thì downvote, kiểu như thế
Nếu đặt tên thì có thể là
python4,python3-gilfoil,python3-gilfreeXu hướng hiện nay tập trung vào Python không có GIL khiến tôi thấy khá lạ. Nhóm Faster CPython từng đặt mục tiêu tham vọng là tăng hiệu năng CPython thêm 50% ở mỗi bản phát hành
3.11 có cải thiện thực sự, nhưng còn xa mới đạt 50%, và trong khá nhiều bài kiểm thử của chúng tôi, 3.12 tương đương hoặc còn chậm hơn. Đa luồng thật sự thì rất tuyệt, nhưng trước hết tôi muốn hiệu năng đơn luồng được cải thiện hơn rất nhiều
Tất nhiên tôi thừa nhận nhu cầu của chúng tôi có thể không đại diện cho tất cả mọi người, và tôi biết ơn mọi công sức đã bỏ ra để biến Python thành một ngôn ngữ tuyệt vời. Dù vậy, tôi vẫn tò mò không biết mình đang bỏ sót điều gì
Hiện nay việc dùng nhiều lõi được thực hiện qua multiprocessing, nhưng có rất nhiều hạn chế. Tôi hiểu rằng nhiều interpreter có thể đi kèm với những thứ như coroutine, nhưng tôi vẫn thích một lựa chọn đa luồng thật sự hơn
Trong Python nogil, chẳng hạn nhiều thread có thể gọi mã C với trạng thái chia sẻ có thể truy cập dưới dạng đối tượng Python. Điều này khá cốt lõi đối với machine learning, và thực tế dạng hiện tại của PEP này xuất phát từ nhóm PyTorch
Hiệu năng đơn luồng cũng quan trọng, nhưng với các đoạn quan trọng thì vốn đã có những đường vòng khá tốt như numba, Cython và Mojo
Thứ tự cũng quan trọng. Nếu nogil được đưa vào, một phần đáng kể công việc của faster CPython có thể bị bỏ hoàn toàn, nên các nhóm đã phải phối hợp với nhau
Trong một thế giới lý tưởng, sẽ có cả chế độ nogil lẫn cải thiện hiệu năng đơn luồng. Guido cũng từng ám chỉ rằng ông đang cân nhắc một JIT tinh vi
Python giúp việc thao tác các trừu tượng cấp thấp từ một ngôn ngữ cấp cao trở nên rất thuận tiện. Vì vậy, với tư cách là một lập trình viên Python lâu năm, tôi không quá căng thẳng về GIL
Nếu phải chọn một trong hai, tôi đồng ý rằng với đa số use case, mã đơn luồng nhanh hơn đơn giản là phù hợp hơn. Nhưng cũng không có lý do gì để không có cả hai
Nhìn lại thì thấy rõ, nhưng nếu phía Python biết quá trình chuyển từ 2 sang 3 sẽ dài và đau đớn đến mức nào, có lẽ họ đã cải tổ nội bộ interpreter mạnh tay hơn nhiều
Dù đã trải qua một cuộc chuyển đổi kéo dài 12 năm, hiệu năng đơn luồng vẫn rất tệ, và để đạt được đa luồng thật sự thì vẫn còn vài lần chuyển đổi đau đớn nữa phía trước
Tôi biết cần phải tử tế với phát triển mã nguồn mở, nhưng tôi tự hỏi đến thời điểm nào thì có thể gọi đây là một ngôn ngữ được quản lý rất kém
Những phần tệ nhất của Python là những phần khó thay đổi vì Python quá phổ biến và hệ sinh thái quá lớn. Vì vậy mọi loại thay đổi đều khó hơn do phải tương thích ngược
Người ta có xu hướng bảo vệ Python quá nhanh. Điều quan trọng là phải nhìn nhận khách quan, không thiên vị
Những dự án muốn có hiệu năng và cú pháp Python có thể chuyển sang đó. Python hiện tại trông như đang chật vật giữa nhiều mục tiêu và không đạt mục tiêu nào cho ra hồn
Perl 5/6 từng được nêu làm ví dụ. Ngay cả khi đã rõ là không ai chuyển đổi, vẫn mất thêm khoảng 5 năm nữa mới có nỗ lực làm cho việc đó dễ hơn