17 điểm bởi GN⁺ 2025-12-27 | 1 bình luận | Chia sẻ qua WhatsApp
  • Trình quản lý gói Python uv cho thấy tốc độ cài đặt nhanh hơn hơn 10 lần so với pip, và điều này không đơn thuần vì nó được viết bằng Rust mà bắt nguồn từ các lựa chọn trong thiết kế
  • Yếu tố cốt lõi tạo nên tốc độ là các tiêu chuẩn siêu dữ liệu tĩnh (PEP 518, 517, 621, 658), cho phép xác định phụ thuộc mà không cần thực thi mã
  • uv mạnh dạn loại bỏ các tính năng legacy mà pip vẫn duy trì (.egg, pip.conf, cài đặt Python hệ thống, v.v.) để xóa bỏ các đường đi mã không cần thiết
  • Phần Rust đóng góp gồm giải tuần tự hóa zero-copy, đồng thời không khóa, kiến trúc nhị phân đơn v.v., nhưng chỉ chiếm một phần trong tổng mức cải thiện tốc độ
  • Nhìn chung, trường hợp của uv cho thấy siêu dữ liệu được chuẩn hóa và việc loại bỏ tương thích không cần thiết là chìa khóa của đột phá hiệu năng

Các tiêu chuẩn làm nên tốc độ của uv

  • Sự chậm chạp của pip không phải do cách triển khai, mà do cấu trúc dựa trên setup.py trong quá khứ, nơi muốn biết phụ thuộc thì phải thực thi mã
    • Việc chạy setup.py đòi hỏi cài đặt các phụ thuộc build trước, gây ra “bài toán con gà và quả trứng”
    • Trong quá trình cài đặt có thể xảy ra thực thi mã tùy ý và lỗi lặp đi lặp lại, làm giảm tốc độ cài đặt
  • PEP 518 (2016) giới thiệu pyproject.toml, cho phép khai báo phụ thuộc build mà không cần thực thi mã
  • PEP 517 (2017) tách frontend và backend build, loại bỏ nhu cầu để pip phải hiểu nội bộ của setuptools
  • PEP 621 (2020) chuẩn hóa bảng [project], cho phép kiểm tra phụ thuộc chỉ bằng cách phân tích TOML
  • PEP 658 (2022) đưa siêu dữ liệu gói trực tiếp vào Simple Repository API, nhờ đó có thể lấy thông tin phụ thuộc mà không cần tải wheel
  • PyPI áp dụng PEP 658 vào tháng 5/2023, và uv ra mắt vào tháng 2/2024, xuất hiện như công cụ đầu tiên tận dụng trọn vẹn hạ tầng tiêu chuẩn mới
  • Tương tự Cargo của Rust hay npm, hệ sinh thái Python giờ đây cũng đang chuyển sang đóng gói dựa trên siêu dữ liệu tĩnh

Những gì uv đã loại bỏ

  • Tốc độ của uv đến từ việc loại bỏ các tính năng không cần thiết
    • Không hỗ trợ .egg: pip vẫn xử lý, còn uv thì loại bỏ hoàn toàn
    • Bỏ qua pip.conf: lược bỏ toàn bộ logic tệp cấu hình, biến môi trường và kế thừa
    • Tắt biên dịch bytecode: không chuyển .py thành .pyc, giúp rút ngắn thời gian cài đặt
    • Bắt buộc dùng môi trường ảo: không cài trực tiếp vào Python hệ thống nên loại bỏ mã kiểm tra quyền hạn và an toàn
    • Tuân thủ đặc tả nghiêm ngặt: từ chối các gói sai chuẩn, giúp giảm logic xử lý ngoại lệ
    • Bỏ qua giới hạn trên của requires-python: bỏ qua các ràng buộc phòng thủ như python<4.0, giúp giảm diễn giải phụ thuộc (backtracking)
    • Ưu tiên chỉ mục đầu tiên: nếu tìm thấy gói ở chỉ mục đầu tiên trong nhiều chỉ mục thì dừng ngay, ngăn tấn công dependency confusion và giảm số yêu cầu mạng
  • Tất cả các mục này là ví dụ cho thấy uv đã loại bỏ những đường đi mã mà pip buộc phải thực hiện

Tối ưu hóa có thể làm được ngay cả không dùng Rust

  • Một phần đáng kể tốc độ của uv đến từ tối ưu hóa thiết kế không phụ thuộc ngôn ngữ
    • Dùng yêu cầu HTTP Range để chỉ tải một phần thư mục trung tâm của tệp wheel, tránh phải tải toàn bộ tệp
    • Tải song song để lấy nhiều gói cùng lúc
    • Dùng bộ nhớ đệm toàn cục và hard link để cài cùng một gói vào nhiều môi trường ảo mà không tiêu tốn thêm dung lượng đĩa
    • Diễn giải không phụ thuộc Python: tự phân tích TOML và siêu dữ liệu wheel, chỉ chạy Python khi chỉ có setup.py
    • Dùng thuật toán diễn giải phụ thuộc PubGrub, nhanh hơn cách backtracking của pip và cho thông báo lỗi rõ ràng hơn

Phần Rust thực sự đóng góp

  • Rust đóng vai trò quan trọng ở một số tối ưu hóa mức thấp
    • Giải tuần tự hóa zero-copy dựa trên rkyv để dùng trực tiếp dữ liệu bộ nhớ đệm mà không cần sao chép
    • Cấu trúc dữ liệu đồng thời không khóa để triển khai truy cập song song an toàn
    • Không cần khởi tạo trình thông dịch: uv là một nhị phân tĩnh đơn, loại bỏ chi phí tạo tiến trình Python như ở pip
    • Biểu diễn nén thông tin phiên bản thành số nguyên u64, giúp so sánh và băm nhanh hơn
  • Các yếu tố này có cải thiện hiệu năng, nhưng không phải nguyên nhân chính của toàn bộ mức tăng tốc

Bài học cốt lõi

  • Tốc độ của uv không đến từ Rust, mà đến từ những gì nó không làm
  • Việc chuẩn hóa trong PEP 518·517·621·658 đã tạo nền tảng cho quản lý gói tốc độ cao, và uv hiện thực hóa điều đó bằng loại bỏ legacy và giả định hiện đại
  • pip cũng có thể triển khai tải song song, bộ nhớ đệm toàn cục và diễn giải dựa trên siêu dữ liệu, nhưng 15 năm duy trì tương thích ngược là rào cản
  • Kết quả là pip gần như luôn sẽ chậm, và chỉ những công cụ bắt đầu từ các giả định mới mới có thể cải thiện tốc độ một cách căn bản
  • Bài học dành cho các trình quản lý gói khác là, siêu dữ liệu tĩnh, khám phá phụ thuộc không cần thực thi mã và cấu trúc có thể diễn giải trước là điều thiết yếu
  • Cargo và npm đã áp dụng cách làm này từ trước, còn những hệ sinh thái phải chạy mã để xác định phụ thuộc thì về bản chất sẽ chậm

1 bình luận

 
GN⁺ 2025-12-27
Ý kiến trên Hacker News
  • Tôi thấy bài này giải thích rất tốt hiệu năng của uv từ nhiều góc độ
    Việc được viết bằng Rust cũng có ích, nhưng nỗ lực chuẩn hóa trong 10 năm qua để hệ sinh thái Python thoát khỏi phụ thuộc vào setup.py mới đóng vai trò lớn hơn nhiều

    • Khi từng làm dự án Haskell trước đây, điểm hay không hẳn là bản thân ngôn ngữ mà là khả năng sàng lọc được cộng đồng chuyên gia
      Rust cũng có thể được chọn vì lý do tương tự: nâng mặt bằng năng lực của cộng đồng
    • Nhiều dự án rewrite sang Rust hưởng được hiệu ứng hào quang này
      Họ có thể nhìn lại những lần thử-sai trước đó để thiết kế tốt hơn, rồi cộng thêm ưu điểm riêng của Rust, thành ra như một cú “đấm kép”
  • Tôi đồng ý với nhận định rằng “uv nhanh không phải vì nó là Rust, mà vì nó có nhiều việc không phải làm
    Dù vậy, tôi nghĩ còn quá sớm để kết luận nguyên nhân tốc độ nếu chưa có benchmark
    Ảnh hưởng của PEP 518, 517, 621, 658 là rất lớn, nhưng việc loại bỏ tương thích ngược đóng góp bao nhiêu thì vẫn đáng nghi ngờ
    Ngoài ra cũng chưa bàn đến việc lựa chọn ngôn ngữ đã ảnh hưởng thế nào tới tối ưu hóa
    Việc parser TOML của Cargo nhanh hơn Python rất nhiều cũng là một điểm thú vị

    • So sánh pip bản cũ và bản hiện tại cũng có thể xem là một dạng benchmark
      Thực tế TOML chỉ được đọc khi build nên không chiếm tỷ trọng lớn, nhưng việc phổ biến wheel đã góp phần cải thiện tốc độ
      Bài tham khảo liên quan: setup.py deprecated, wheels are faster
  • Zero-copy deserialization dùng rkyv không phải là kỹ thuật chỉ Rust mới có
    Các ngôn ngữ mức thấp như C/C++ cũng làm được

    • Tôi hiểu ý “chỉ dành cho Rust” ở đây là “không thể làm trong Python”
      Câu “không có khởi động interpreter” cũng nằm trong cùng ngữ cảnh đó
    • Vì rất khó hiện thực zero-copy bằng Python, nên tôi công nhận Rust đã làm điều này an toàn và dễ dàng hơn
    • Cuối cùng thì đây vẫn là cuộc so sánh giữa Rust và Python
  • Nội dung bài viết thì tốt, nhưng văn phong được LLM gọt giũa nghe quá giả tạo
    Có khi rồi sẽ đến lúc người ta phải phục hồi lại chất người cho những bài viết bị LLM làm hỏng

    • Tác giả này cũng từng lên HN với bài về SBOM và Lockfile
      Có vẻ là chuyên gia về bảo mật chuỗi cung ứng, nhưng bài đó cũng mang cảm giác bị biến chất bởi văn phong mơ hồ đặc trưng của LLM
    • Ngược lại, có người lại hoàn toàn không thấy mùi LLM và cho rằng văn phong rất tự nhiên
    • Giờ mà tôi ngửi thấy mùi AI trong bài viết là đóng tab ngay
      Những prompt cố định khiến mọi bài đều giống nhau, làm tôi thấy Internet như đang nói cùng một giọng
  • Tôi không hiểu lắm bầu không khí cuồng nhiệt trước tốc độ của uv
    Phần lớn người dùng Python có lẽ sẽ không xếp tốc độ cài package vào top 10 mối bận tâm
    Tôi cũng dùng Python hằng ngày nhưng không cảm nhận rõ lắm

    • Ở công ty cũ, cập nhật dependency bằng poetry mất từ 5 đến 30 phút
      Nếu thất bại thì lại phải chờ thêm 30 phút nữa, nên uv thực sự là một trải nghiệm dễ chịu
    • Tôi đã dùng Python hơn 20 năm, và pip install từng chiếm tỷ trọng lớn trong thời gian deploy
      Tôi đã tốn rất nhiều thời gian cố tăng tốc bằng caching
    • Trong ứng dụng monolith phục vụ công việc của tôi, poetry install mất 2 phút còn uv sync chỉ mất vài giây
      Tiết kiệm 2 phút ở mỗi lần chạy CI thì hiệu ứng cộng dồn là rất lớn
    • Ngay cả khi chạy uvx sometool, việc tạo virtualenv và cài dependency cũng xong trong vài giây, làm thay đổi hoàn toàn luồng làm việc
    • Với một người dùng Python lâu năm như tôi, tốc độ của uv là kiểu thay đổi “nâng cấp chất lượng cuộc sống”
      Giờ rất khó quay lại với những dự án không có uv
  • Một phần kỹ thuật tối ưu tốc độ của uv có vẻ cũng có thể mang sang pip
    Ví dụ: tải song song, tạo .pyc trì hoãn, bỏ qua egg, kiểm tra phiên bản, v.v.
    Nhưng uv xử lý venv quá tốt nên có lẽ cũng chẳng cần động vào pip nữa
    Tóm lại, điểm quan trọng là không phải chỉ nhờ Rust mà pip không còn chỗ để nhanh hơn

  • Các lập trình viên chọn ngôn ngữ nhanh thường vốn đã có mindset tối ưu hiệu năng
    Chính thái độ đó ảnh hưởng tới hiệu năng nhiều hơn bản thân ngôn ngữ

  • Lý do uv bỏ qua cận trên python<4.0 là một điểm khá thú vị
    Hầu hết package đặt giới hạn đó một cách phòng thủ, vì sợ hỏng trên Python 4, chứ thực tế có thể chẳng có vấn đề gì
    Giới hạn cận trên là nỗ lực giải quyết những vấn đề giả định hơn là vấn đề thực tế

    • Không phải uv bỏ qua mọi cận trên, mà có vẻ chỉ bỏ qua riêng 4.0
      Các ràng buộc như python<3.0 vẫn quan trọng, nên những trường hợp như vậy vẫn cần bị chặn
  • Việc PEP 658 được áp dụng năm 2023 và uv xuất hiện năm 2024 không phải là trùng hợp
    Hệ sinh thái đã sẵn sàng nên công cụ như uv mới có thể xuất hiện
    Nhưng tôi vẫn tò mò vì sao các maintainer package lại chấp nhận thay đổi này
    Chắc hẳn cũng có người thấy setup.py đang chạy tốt, vậy động lực chuyển sang pyproject.toml là gì

    • Thực ra setup.py đã gây bất tiện cho nhiều người
      Chẳng hạn ngay cả Requests đến giờ vẫn chưa tương thích hoàn toàn với PEP 517/518/621
      Sau một năm rưỡi mà bản minor release vẫn bị trì hoãn, trong thời gian đó còn phát sinh vấn đề build
    • Vì khai báo tĩnh an toàn hơn và có lợi hơn về hiệu năng
      Dù vậy, tôi vẫn thắc mắc vì sao pip không tận dụng điều này đầy đủ hơn
  • Cách nói “những nhánh code không làm thì không cần phải chờ” là chưa chính xác
    Chỉ những đoạn code không chạy mới thực sự tiết kiệm thời gian
    Ví dụ, không hỗ trợ .egg cũng không ảnh hưởng đến tốc độ nếu đó vốn đã là định dạng bị loại bỏ
    Sẽ tốt hơn nếu có dữ liệu định lượng cho thấy từng hạng mục thực sự tiết kiệm được bao nhiêu thời gian
    Dù sao thì nhìn chung đây vẫn là một bài viết được tổng hợp khá tốt