3 điểm bởi GN⁺ 2025-12-26 | 1 bình luận | Chia sẻ qua WhatsApp
  • Trình thông dịch tail-calling của CPython cho thấy hiệu năng nhanh hơn khoảng 15% so với cách hiện tại trong môi trường Windows x86-64
  • Trên macOS AArch64 (XCode Clang), cũng ghi nhận cải thiện hiệu năng khoảng 5%, còn trên Windows thì tận dụng tính năng thử nghiệm của MSVC 2026
  • Trong benchmark pyperformance, phần lớn các bài test đều cho thấy tốc độ được cải thiện, một số trường hợp tăng tối đa tới 78%
  • Nguyên nhân chính của mức tăng hiệu năng được phân tích là do đặt lại heuristic tối ưu hóa của compiler và cải thiện khả năng inline
  • Khi Python 3.15 phát hành chính thức, tính năng này dự kiến sẽ được áp dụng mặc định trong các bản build dựa trên Visual Studio 2026

Cải thiện hiệu năng của trình thông dịch tail-calling

  • Trình thông dịch tail-calling của CPython được đo là nhanh hơn khoảng 15% so với trình thông dịch switch-case hiện có trên Windows x86-64
    • Theo pyperformance, trung bình hình học tăng 15~16%
    • Một số benchmark tăng tốc tối đa 78%, trong khi một số ít chậm hơn 60%
  • Trên macOS AArch64 (XCode Clang), xác nhận mức cải thiện hiệu năng khoảng 5%
  • Kết quả này có giá trị với giả định rằng sẽ không có thay đổi trong chu kỳ phát triển của Python 3.15

So sánh cấu trúc trình thông dịch

  • Các cách triển khai trình thông dịch bằng C được chia thành ba kiểu: switch-case, computed gototail-call threaded
    • switch-case: xử lý rẽ nhánh theo từng lệnh
    • computed goto: phần mở rộng của GCC/Clang, nhảy trực tiếp tới địa chỉ rẽ nhánh
    • tail-call threaded: tách mỗi handler bytecode thành một hàm riêng, rồi tail call sang hàm tiếp theo
  • Trước đây, compiler C không đảm bảo tối ưu hóa tail call nên có nguy cơ tràn stack
  • Với các thuộc tính __attribute__((musttail)) của Clang và [[msvc::musttail]] của MSVC, giờ đây có thể bắt buộc tail call

Kết quả build bằng MSVC 2026 cho Windows

  • Trong bản build CPython dùng tính năng thử nghiệm của MSVC, đa số benchmark đều tăng tốc
    • Ví dụ kết quả:
      • spectralnorm: 1.48 lần
      • nbody: 1.35 lần
      • bm_django_template: 1.18 lần
      • xdsl: 1.14 lần
  • Nội dung này đã được phản ánh chính thức trong tài liệu “What’s New” của Python 3.15
    • Có thể sử dụng trình thông dịch tail-calling trong các bản build bằng Visual Studio 2026 (MSVC 18)
    • Thư viện Python thuần có thể nhanh hơn khoảng 15%, còn script nhỏ có thể tăng tốc tối đa 40%

Nguyên nhân của cải thiện hiệu năng

  • Tail calling khởi tạo lại heuristic tối ưu hóa của compiler, từ đó dẫn tới việc sinh mã hiệu quả hơn
  • Vòng lặp trình thông dịch CPython hiện tại gồm một hàm đơn dài khoảng 12.000 dòng nên thường xuyên thất bại trong tối ưu hóa inline
    • Có nhiều trường hợp compiler từ chối inline để tránh làm tăng kích thước mã
  • Với cách tail calling, các hàm được tách riêng nên những hàm đơn giản có thể được inline
    • Ví dụ, các hàm đơn giản như PyStackRef_CLOSE_SPECIALIZED có thể được inline
  • Hiện tượng tương tự cũng được ghi nhận trong các bản build PGO (profile-guided optimization)

Cách build và sử dụng

  • Hiện tại chỉ có thể build từ mã nguồn
    • Trong môi trường Visual Studio 2026, build bằng lệnh sau
      $env:PlatformToolset = "v145"
      ./PCbuild/build.bat --tail-call-interp -c Release -p x64 --pgo
      
  • Về sau, khi quá trình phát triển Python 3.15 ổn định hơn, sẽ có phân phối binary chính thức

1 bình luận

 
GN⁺ 2025-12-26
Ý kiến trên Hacker News
  • Chia sẻ đoạn mã cốt lõi mà lẽ ra nên được đưa vào bài blog
    Đây là ví dụ cho thấy sự khác biệt trong cách định nghĩa thuộc tính musttailpreserve_none giữa MSVC và Clang
    Các thuộc tính này phải được gắn vào declarator của hàm, và không hoạt động ở vị trí function specifier
    Liên kết mã liên quan
    Bình luận này cũng gợi cảm giác rằng Microsoft dường như chỉ tiết lộ các tính năng không công khai như vậy cho những dự án mà họ cho là quan trọng
    • Tôi đã nhầm. [[msvc::musttail]] thực ra là thuộc tính đã được tài liệu hóa chính thức
      Tôi sẽ sửa lại bài blog để phản ánh điều đó
      Bình luận HN liên quan
    • Đặt câu hỏi: “Họ nói vì nó quan trọng, hay vì việc đó có lợi cho chính họ?”
  • Gợi nhớ tới trường hợp trước đây ở Python 3.14 khi bug của LLVM 19 khiến mức cải thiện hiệu năng bị báo cáo sai, và hy vọng lần này không có vấn đề tương tự
    Sau khi đọc bài, người này cho rằng cách tiếp cận ưu tiên tính minh bạch và phản hồi nhanh là ổn
    Sẽ còn tốt hơn nếu có kiểm chứng bằng cross-compiler hoặc kiểm toán độc lập, nhưng họ vẫn tin tưởng nhờ sự minh bạch hoàn toàn của tác giả
    • Tác giả nói rằng sai sót khi đó lại là một tai nạn may mắn
      Vì được công bố sớm nên Nelson đã phát hiện bug của Clang 19, nhờ đó có thể sửa trước khi phát hành chính thức
      Lần này có thêm hai cải tiến là dispatch logic và inlining, nên họ tự tin hơn
      MSVC có thể biến trình thông dịch switch-case thành threaded code trong một số điều kiện nhất định, nhưng CPython quá phức tạp nên tối ưu đó không được áp dụng
      Thay vào đó, cách tiếp cận tail call cho phép người viết mã C có nhiều quyền kiểm soát hơn
      Tham khảo: điều kiện threaded code của MSVC, vấn đề liên quan đến forceinline
    • Ưu điểm của thiết kế mới là ít phụ thuộc hơn vào sự thất thường của tối ưu hóa trình biên dịch
      Trước đây các tối ưu như tail duplication thay đổi tùy theo quyết định của compiler, còn giờ trình thông dịch có thể trực tiếp biểu đạt dạng mã máy mà nó muốn
      Liên kết thảo luận trước đó
  • Có người chia sẻ video bài nói tại EuroPython 2025 về các vấn đề compiler trong quá khứ
  • Một người nói rằng gần đây họ lại đang làm ứng dụng GUI cho Windows bằng Python
    Họ chọn Python vì hệ sinh thái VS quá nặng nề so với C#/MAUI
    Tkinter thì bất tiện, còn Qt lại có độ khó học khá cao, nên họ dùng kết hợp wxGlade + wxPython
    Chỉ cần một dependency duy nhất có thể cài bằng pip, và họ thích cảm giác sử dụng đậm chất Pythonic
    Vì vậy các cải thiện runtime trên Windows là tin vui
    • Tôi thích tổ hợp Python + Qt/PySide hơn
      Làm UI nhanh bằng QtCreator rồi gắn logic bằng Python giúp tốc độ phát triển rất nhanh
    • Cũng có người gợi ý pyfltk. Trên GNU/Linux nó hoạt động khá ổn
    • Nếu GUI quan trọng thì LINQPad cũng đáng cân nhắc. Nó nằm ở khoảng giữa giữa scripting và các công cụ nặng hơn
    • Có người khuyên dùng binding ImGui cho Python
      Không giống retained mode như Tkinter hay Qt, nó dùng kiểu immediate mode, nên đặc biệt hữu ích cho công cụ nội bộ
      Dự án imgui_bundle
  • Có người đặt vấn đề: “Chẳng phải đây là một bài toán tối ưu hóa độ khó thấp sao?”, và thắc mắc vì sao vòng lặp interpreter đến giờ vẫn chưa được tối ưu hoàn toàn
    Họ nói rằng đã tưởng nó phải được viết bằng assembly cho từng ISA chính rồi
    • Ngược lại, có người cho rằng chính bản cập nhật này cho thấy vòng lặp đã được tối ưu hóa ở mức cực cao
      [[msvc::musttail]] là thuộc tính rất mới, chỉ được thêm vào MSVC 14.50 (ra mắt tháng trước), vậy mà nhóm CPython đã tận dụng nó trong vài tuần để đạt cải thiện hiệu năng
      Tài liệu MSVC musttail
    • Python ngay từ đầu đã nhắm tới sự đơn giản hơn là tốc độ
      Guido ưu tiên tính đơn giản của mã nguồn, nên việc đưa JIT vào diễn ra chậm, rồi sau đó mới có các nỗ lực như PEP 744 (JIT Compilation)
    • Không nên kỳ vọng quá mức vào mã nguồn mở
      Tối ưu hóa bằng assembly là ác mộng bảo trì, và nút thắt thực sự của Python là hệ thống đóng gói
    • Dù sao thì những người thực sự nhạy cảm với hiệu năng cũng không chạy Python trên Windows
  • Có người hỏi: “Vì sao trình thông dịch Python lại chậm hơn V8 nhiều đến vậy?”
    • JavaScript dùng biên dịch JIT còn CPython thì không
      PyPy nhanh nhờ JIT nhưng lại không tương thích với extension C
      Mô hình luồng của Python cũng khiến việc tối ưu khó hơn
      Trong khi đó JS là single-thread nên đơn giản hơn
      Python còn có thể lách qua bằng extension C, nên áp lực tối ưu chính CPython từ trước tới nay thấp hơn
    • Có ý kiến cho rằng nhân lực và chất lượng kỹ thuật của Google tạo ra khác biệt lớn
      Ngoài ra CPython không thể phá vỡ tính tương thích vì có một hệ sinh thái extension C khổng lồ
      Còn V8 thì có thể tự do thay đổi cấu trúc bên trong
    • Python động hơn rất nhiều, đến cả truy cập thuộc tính cũng đi qua giao thức descriptor
      Ngoài ra nó còn phải duy trì ABI C ổn định, nên JIT khó có thể tự do phân tích mã
    • Python là ngôn ngữ động hơn JS rất nhiều, và các binding FFI làm thay đổi nội bộ bị hạn chế
      Có nhắc đến việc PyPy đã vất vả ra sao khi phải đáp ứng các ràng buộc này
    • JS đã được Google rót nguồn lực khổng lồ để tối ưu nhằm thống trị web, còn Python thì dành nhiều tài nguyên hơn cho sự phát triển của ngôn ngữ
      Ngoài ra JS chỉ cần hỗ trợ JS thuần, còn Python phải duy trì hệ sinh thái extension bên ngoài nên bị hạn chế nhiều hơn trong tối ưu hóa
  • Có người nói biểu đồ benchmark mới khá thú vị và hỏi nó được tạo bằng công cụ nào
    Họ cũng chia sẻ rằng mình từng dùng mitata để đo hiệu năng thư viện JS
    PR tối ưu hóa Immer JS
  • Có người nhắc rằng Matt Godbolt từng nói trình thông dịch dựa trên tail-call phù hợp hơn với branch predictor của CPU
  • Có bình luận hỏi rằng câu đầu của bài có hai lỗi chính tả, liệu đó có phải là lỗi cố ý để trông giống nội dung AI tạo ra hay không
    • Tác giả đáp lại: “Cảm ơn, đã sửa rồi”
    • Người khác đùa rằng để không trông giống AI thì cứ tự viết lấy
      Họ châm biếm các đặc điểm điển hình của bài do AI viết như đoạn văn ngắn, giọng điệu quá tích cực, thiếu chiều sâu, v.v.
  • Có người đặt câu hỏi: “Nếu nhóm Python thấy tail call hữu ích, liệu ngôn ngữ này cũng sẽ hỗ trợ tail call không?”