Nỗi ám ảnh mang tên pip và ma trận môi trường Python
Chắc hẳn bạn không còn lạ gì cảnh ngồi chờ pip install -r requirements.txt trên CI/CD runner. Quá trình phân giải dependency (dependency resolution) kéo dài từ 5 đến 10 phút là chuyện cơm bữa. Đổi máy làm việc lại là một cực hình khác: máy đang có sẵn Python 3.10 nhưng dự án đòi hỏi bản 3.12. Bạn phải cấu hình lại pyenv, tạo venv thủ công, rồi sốt ruột đợi Poetry giải quyết xung đột thư viện.
Vấn đề nằm ở kiến trúc lõi. Phần lớn công cụ truyền thống trong hệ sinh thái Python được viết bằng chính Python. Khi đồ thị phụ thuộc phình to, thuật toán backtracking kèm cơ chế I/O đơn luồng lập tức trở thành nút thắt cổ chai. Đã vậy, mỗi project lại nhân bản một bản sao thư viện riêng, âm thầm nuốt trọn 30-40 GB dung lượng ổ SSD của bạn.
Đầu năm 2024, Astral — đội ngũ đứng sau linter siêu tốc Ruff — đã tung ra uv. Được viết 100% bằng Rust, uv đạt tốc độ giải quyết package nhanh gấp 10-100 lần so với pip và Poetry. Công cụ này xử lý trọn gói từ việc tải runtime Python, quản lý virtualenv cho đến việc khóa dependencies, thu gọn toàn bộ dàn công cụ cồng kềnh vào một binary duy nhất.
1. Quick start: Trải nghiệm uv chỉ sau 5 phút
Không cần cấu hình phức tạp. Bạn có thể kiểm chứng ngay sự khác biệt về tốc độ qua vài lệnh cơ bản.
Bước 1: Cài đặt uv
Với Linux hoặc macOS, bạn mở terminal và chạy lệnh:
curl -LsSf https://astral.sh/uv/install.sh | sh
Với Windows (PowerShell):
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Kiểm tra cài đặt thành công:
uv --version
Bước 2: Khởi tạo dự án và chạy ứng dụng đầu tiên
# Tạo thư mục và khởi tạo dự án với chuẩn pyproject.toml
mkdir demo-uv && cd demo-uv
uv init
# Thêm thư viện: uv tự động tạo virtualenv nếu chưa tồn tại
uv add requests pydantic
# Chạy file trực tiếp không cần kích hoạt venv thủ công
uv run hello.py
Toàn bộ thao tác tải và liên kết gói chỉ mất khoảng 0.2 đến 0.5 giây nếu package đã nằm trong cache máy. Cảm giác mượt mà và tức thì khác hẳn trải nghiệm thường thấy với pip.
2. Giải thích chi tiết: uv thay thế pip, venv và Poetry như thế nào?
2.1. Drop-in replacement cho pip
Bạn chưa muốn đổi cấu trúc project cũ? Hãy dùng nhóm lệnh uv pip. Cú pháp tương thích hoàn toàn với pip nhưng hiệu năng vượt trội:
# Tạo virtualenv trong khoảng 15-30ms thay vì 1-2 giây
uv venv
# Kích hoạt môi trường ảo (Linux/macOS)
source .venv/bin/activate
# Cài đặt file requirements với tốc độ Rust
uv pip install -r requirements.txt
# Xuất danh sách package chuẩn xác
uv pip freeze > requirements.txt
2.2. Tự động tải và ghim phiên bản Python
Bạn có thể bỏ qua pyenv. uv tự động tải các bản build Python độc lập (standalone builds) trực tiếp từ kho phân phối an toàn:
# Cài đặt nhiều bản Python song song trong vài giây
uv python install 3.11 3.12
# Liệt kê tất cả phiên bản Python tìm thấy trên hệ thống
uv python list
# Ghim cố định phiên bản cho project qua file .python-version
uv python pin 3.12
2.3. Quản lý dự án toàn diện thay cho Poetry
uv áp dụng triệt để chuẩn PEP 621 với pyproject.toml và sinh file khóa uv.lock đa nền tảng (chạy nhất quán trên cả Windows, Linux và macOS):
# Cài package cho ứng dụng chính
uv add fastapi uvicorn
# Tách riêng dependency cho môi trường dev hoặc test
uv add --dev pytest ruff
# Gỡ bỏ sạch sẽ package và các dependency con liên quan
uv remove requests
# Đồng bộ chính xác môi trường theo uv.lock (cực kỳ hữu ích cho CI/CD)
uv sync
3. Tính năng nâng cao: Script độc lập và công cụ CLI
3.1. Chạy script đơn lẻ với Inline Metadata (PEP 723)
Thay vì phải dựng hẳn một virtualenv chỉ để chạy một file automation nhỏ, bạn khai báo dependency trực tiếp ở đầu file:
# /// script
# requires-python = ">=3.11"
# dependencies = [
# "httpx",
# "rich",
# ]
# ///
import httpx
from rich import print
resp = httpx.get("https://api.github.com/repos/astral-sh/uv")
print(resp.json())
Chạy script bằng một lệnh duy nhất:
uv run script.py
uv sẽ tự tạo môi trường tạm thời, kéo httpx cùng rich về chạy, sau đó tự thu dọn sạch sẽ. Môi trường gốc của máy bạn vẫn nguyên vẹn.
3.2. Chạy nhanh CLI tool không cần cài global (tương tự npx)
Lệnh uvx (viết tắt của uv tool run) giúp bạn gọi nhanh bất kỳ công cụ dòng lệnh nào của Python:
# Format code bằng Ruff mà không cần cài ruff vào máy
uvx ruff format .
# Dùng HTTPie test nhanh một API endpoint
uvx httpie https://httpbin.org/get
4. Kinh nghiệm thực chiến khi áp dụng uv
- Tận dụng Global Cache: uv dùng cơ chế hard link trên cùng phân vùng đĩa. Nếu 10 project của bạn cùng khai báo
torchhaypandas, ổ cứng chỉ tốn dung lượng đúng một lần. Bạn có thể giải phóng bớt các build cũ bằng lệnhuv cache prune. - Cắt giảm 80% thời gian build Docker: Hãy copy trước binary uv qua multi-stage build (
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv), sau đó chạyuv sync --frozen --no-install-project. Thời gian build Docker image trên pipeline thường giảm từ 3-4 phút xuống còn chưa đầy 25 giây. - Kiểm tra regex trước khi đưa vào script: Khi viết script tự động parse log hệ thống, bạn rất dễ gặp lỗi escaping ký tự
\trong chuỗi regex. Thay vì chạy thử đi thử lại bằng terminal, bạn có thể kiểm tra trước chuỗi pattern trên web tool như toolcraft.app/vi/tools/developer/regex-tester. Khi chuỗi regex đã bắt đúng data mẫu, hãy copy vào script Python rồi thực thi bằnguv run. - Đồng bộ trên Git hook: Kết hợp uv với
pre-commitgiúp toàn bộ lập trình viên trong team luôn chạy cùng một phiên bản linter, dẹp bỏ hoàn toàn lỗi “chạy trên máy tôi vẫn bình thường”.
Việc chuyển sang uv không chỉ giúp bạn tiết kiệm vài chục giây chờ cài package. Quan trọng hơn, nó chuẩn hóa toàn bộ luồng làm việc với Python từ máy local lên đến CI/CD pipeline, mang lại cảm giác mượt mà và chắc chắn khi phát triển phần mềm.
