- Bên trong zig build được tách thành các tiến trình configurer và maker, còn đồ thị build do
build.zig tạo ra được tuần tự hóa thành một tệp cấu hình nhị phân
- Tiến trình cha lưu vào bộ nhớ đệm tệp cấu hình và biên dịch maker bất đồng bộ ở chế độ Release; maker chỉ cần được biên dịch một lần vào bộ nhớ đệm toàn cục cho mỗi phiên bản Zig
- Khi người dùng thay đổi
build.zig, không còn phải biên dịch lại toàn bộ hệ thống build cùng lúc, giúp giảm chi phí thời gian khi bổ sung các tính năng như --watch, --fuzz, --webui
- Thời gian chạy trung bình của
zig build --help giảm từ 150ms xuống 14.3ms, còn số chu kỳ CPU, số lệnh và truy cập bộ nhớ đệm cũng giảm trong khoảng 94~96%
- Phần lớn API vẫn tương thích, nhưng việc quan sát trực tiếp
b.args được thay bằng addPassthruArgs(), và Zig 0.17.0 dự kiến sẽ ra mắt trong vài tuần tới
Thay đổi cấu trúc hệ thống build
- Nhánh lớn đã được hợp nhất, tách nội bộ
zig build thành tiến trình configurer và tiến trình maker
- Trong cấu trúc cũ, tệp
build.zig và toàn bộ phần triển khai của hệ thống build được biên dịch thành một tiến trình lớn ở chế độ Debug, rồi build.zig tạo đồ thị build trong bộ nhớ trước khi “build runner” thực thi nó
- Trong cấu trúc mới,
build.zig được biên dịch thành một tiến trình configurer nhỏ ở chế độ Debug, và đồ thị build được tuần tự hóa thành một tệp cấu hình nhị phân
- Tiến trình cha
zig build phát hiện tệp cấu hình, lưu vào bộ nhớ đệm cho lần chạy tiếp theo, đồng thời biên dịch bất đồng bộ maker ở chế độ Release để đảm nhiệm việc thực thi đồ thị build
- Khi tệp cấu hình và quá trình biên dịch maker đã sẵn sàng, maker sẽ nhận tệp cấu hình và thực thi; nhờ bộ nhớ đệm toàn cục, maker chỉ cần được biên dịch một lần cho mỗi
zig version
Tác động của việc cải thiện tốc độ
- Mục tiêu cốt lõi là tăng tốc
zig build, và khi người dùng thay đổi build.zig, sẽ không còn phải biên dịch lại toàn bộ hệ thống build cùng lúc
- Khi các tính năng như
--watch, --fuzz, --webui được đưa vào, điều này càng có ý nghĩa vì thời gian của zig build sẽ không tăng theo số lượng tính năng của hệ thống build
- Nếu xác định không có thay đổi, có thể tái sử dụng cấu hình trước đó mà không cần chạy lại logic
build.zig
- Ví dụ, ngay cả khi thêm
-freference-trace vào dòng lệnh zig build, cũng không cần chạy lại logic build.zig một cách không cần thiết
- Vì tiến trình thực thi đồ thị build thực tế được biên dịch với tối ưu hóa được bật, nên giai đoạn thực thi cũng nhanh hơn
Kết quả benchmark
- Thời gian chạy trung bình của
zig build --help đã giảm từ 150ms trong cấu trúc cũ xuống còn 14.3ms trong cấu trúc mới
- Thời gian đồng hồ thực giảm từ
150ms xuống 14.3ms, tức giảm 90.4%; số chu kỳ CPU giảm từ 593M xuống 24.1M, tức giảm 95.9%
- Số lệnh giảm từ
995M xuống 43.7M, tức giảm 95.6%; số lần truy cập bộ nhớ đệm giảm từ 25.8M xuống 1.46M, tức giảm 94.3%
- Peak RSS giảm từ
84.8MB xuống 78.5MB, tức giảm 7.4%
- Khác biệt lớn nhất đến từ việc chuyển từ mô hình chạy logic
build.zig cho mọi lệnh zig build sang mô hình tái sử dụng cấu hình tuần tự hóa đã được lưu đệm
Ảnh hưởng đến công cụ và khả năng tương thích
- Các công cụ bên thứ ba như ZLS có thể hưởng lợi bằng cách tiêu thụ trực tiếp tệp cấu hình đã tuần tự hóa thay vì fork và duy trì build runner
- Dù cơ chế nội bộ đã thay đổi đáng kể, xét từ góc độ API thì phần lớn vẫn giữ tương thích
- Các ngoại lệ tương ứng với những thay đổi đã được tổng hợp trong PR đã hợp nhất
Những thay đổi phá vỡ chính
- Thay đổi mà nhiều người dùng có khả năng gặp nhất là việc loại bỏ kiểu dùng quan sát trực tiếp
b.args
- Mã cũ:
if (b.args) |args| {
run_cmd.addArgs(args);
}
run_cmd.addPassthruArgs();
- Với thay đổi này, script build sẽ không còn quan sát được các đối số đó nữa, tức là một tính năng đã bị loại bỏ
- Đổi lại, dù thay đổi các đối số đó thì cũng không còn cần phải biên dịch lại script build từ mã nguồn
Kiểm thử và lịch phát hành
- Người dùng muốn tác động đến định hướng của Zig có thể nâng dự án lên phiên bản phát triển để thử các thay đổi mới và gửi phản hồi
- Zig
0.17.0 dự kiến sẽ được phát hành trong vài tuần tới
- Do không có thời gian để thử trước, nên ngay cả khi build bị hỏng ở
0.17.0, vẫn còn đủ cơ hội để đưa bản sửa vào tag 0.17.1
1 bình luận
Ý kiến trên Hacker News
Tôi đã thử chuyển một phần code sang Zig 0.16.0 và kết quả khá đáng hài lòng
Phần bị ảnh hưởng là khá nhiều, nhưng bản thân các thay đổi đều tốt và có vẻ đi theo hướng làm tương lai của ngôn ngữ sáng sủa hơn
Đặc biệt, cơ chế nhập/xuất mới cho phép viết mã hiệu quả với hình thức đẹp mắt trong cả triển khai đơn luồng, đa luồng lẫn vòng lặp sự kiện
Nếu từ sau 0.16.0 bạn vẫn chưa dùng lại Zig thì rất nên xem qua. Ghi chú phát hành lần này dài kinh khủng
https://ziglang.org/download/0.16.0/release-notes.html
Theo tôi biết thì nó còn chậm hơn trước
Hy vọng các bản phát hành tới sẽ xử lý vấn đề “đích dispatch được biết ở thời điểm biên dịch nhưng vẫn còn động”, từ đó giảm thất thoát hiệu năng
Tôi đoán rằng khi gọi
io.asynctrong một triển khai IO dựa trên vòng lặp sự kiện, bên trong nó sẽ khởi động thứ gì đó như một “task”, và future sẽ là handle của nóĐiều tôi không hiểu là khi gọi
future.await(io)thì chuyện gì xảy ra. Triển khai IO có cách nào đó tạm dừng hàm hiện tại rồi tiếp tục lại khi future được giải quyết không? Nếu vậy thì có nghĩa mọi hàm trong Zig đều là coroutine không stack sao?.use_llvm = truetrong bản build ZigSau vài tháng dùng Zig, tôi tin chắc đây là một ngôn ngữ tuyệt vời để làm công cụ
Nó rất hợp để cầm lên và nhanh chóng ráp thử ý tưởng một cách tự do, và ở mỗi chỗ bị vướng thì những người tạo ra nó thường đã nghĩ sẵn một lời giải thoải mái
Nhưng nó cũng không ép bạn phải dùng ngôn ngữ theo kiểu “đúng chuẩn”
Giờ nó đã trở thành ngôn ngữ mặc định của tôi cho việc “mày mò trong gara”
Với tôi đây là vấn đề năng suất khá lớn
Ngôn ngữ mặc định của tôi để “mày mò trong gara” là Python. Cú pháp nhẹ, cảm giác sử dụng không vướng víu, thư viện chuẩn phong phú, thiếu gì thì package cũng có hết
Điểm mạnh của Zig là gì?
Xem video phỏng vấn Andrew Kelley xong tôi thấy muốn học thử Zig: https://www.youtube.com/watch?v=iqddnwKF8HQ
Câu trả lời của Andrew thì ổn, nhưng bầu không khí chung mang cảm giác tâng bốc quá mức
Tôi từng muốn dùng Zig, nhưng ngôn ngữ này vẫn thay đổi quá nhanh
Mỗi bản phát hành đều phá vỡ API, nên rất khó vừa học ngôn ngữ, vừa gỡ lỗi hệ thống build, vừa theo kịp việc hiện thực hóa thứ mình thật sự muốn làm
Sau khi xem phỏng vấn của JetBrains tôi cũng muốn thử lại, nhưng có lẽ sẽ đợi tới khi ra 1.0
Từ lâu tôi đã nghĩ về một ý tưởng mà tôi gọi là lập trình kép
Đó là cách tổ chức stack chỉ với đúng hai ngôn ngữ: một ngôn ngữ bậc cao và một ngôn ngữ bậc thấp
Càng viết được nhiều bằng ngôn ngữ bậc cao càng tốt, và chỉ hạ xuống ngôn ngữ bậc thấp khi thật sự cần
Vấn đề là nếu bạn chưa thực sự rất giỏi ngôn ngữ bậc thấp đó, thì trước khi làm phần việc mức thấp, rất có thể bạn sẽ phải làm quen lại với ngôn ngữ ấy
Vì thế C++ hay Rust trở nên khó viết hơn C, và với tôi C là lựa chọn mặc định. Nhưng C cũng có những vấn đề đã quá rõ
Zig có vẻ lấp đúng điểm ngọt đó: đủ đơn giản để dễ nhặt lại sau một quãng nghỉ dài, nhưng vẫn có các công cụ hiện đại giúp việc lập trình dễ hơn
Tôi muốn làm được càng nhiều càng tốt ở ngôn ngữ bậc thấp, và chỉ nâng lên ngôn ngữ bậc cao khi sự tiện lợi đáng để trả giá
Roc cho phép làm điều này. Mọi chương trình đều có một platform được viết bằng ngôn ngữ bậc thấp, còn chương trình Roc thì dùng API mà platform đó phơi ra
https://www.roc-lang.org/
Tất nhiên việc cân bằng giữa bậc cao và bậc thấp thế nào thì mỗi người tự chọn
Các model được hiện thực bằng Cython, còn API cho người dùng thì cung cấp bằng Python
Giờ tôi làm mọi thứ bằng Rust, và đặc biệt nhờ hệ thống kiểu kiểu OCaml nên tôi vẫn chưa tìm ra thứ gì mình không làm được
Lua vốn được thiết kế như ngôn ngữ nhúng nên rất hợp cho khả năng tương tác, đồng thời cũng đủ bậc cao để dễ dùng
Có lý do để Factorio dùng Lua làm ngôn ngữ scripting
Điều tôi thích ở quá trình phát triển Zig là họ đổ lượng công sức đáng kinh ngạc vào công cụ và vòng phản hồi cho lập trình viên, hơn là chỉ thêm tính năng ngôn ngữ
Một ngôn ngữ mới vẫn có thể sống sót một thời gian dù thiếu đi một tính năng nào đó
Nhưng nếu mỗi lần biên dịch, liên kết, cập nhật phụ thuộc đều thấy chậm chạp, thì khả năng sống sót sẽ khó hơn nhiều
Việc tập trung biến chu kỳ phát triển từ đơn vị giây xuống mili giây có vẻ là một khoản đặt cược tốt về lâu dài
Tôi ngạc nhiên khi thấy câu “dự định phát hành 0.17.0 trong vài tuần tới”
0.16 chẳng phải đã mất hơn một năm sao?
Tôi không ngờ 0.17 lại ra nhanh như vậy, và hôm nay biết được điều này thật sự rất vui
Nghe có vẻ là tin tốt. Thời gian biên dịch của Zig vốn đã rất tốt, và có vẻ thay đổi này sẽ còn cải thiện hơn nữa
Đây rõ ràng là một mục tiêu quan trọng, và các cột mốc để đạt được cũng đã rõ, nhưng trên thực tế rất khó gọi khoảng thời gian chờ đầy đau đớn khi biên dịch lần đầu một project trống, hoặc khi ZLS build lại sau
direnv allow, là “rất tốt”zig test file.zig -OReleaseSafethì trên máy tôi cũng mất vài giâyMỗi lần sửa file lại tiếp tục mất từng đó thời gian. Tôi đang dùng 0.16 hoặc master nên cũng không phải do toolchain quá cũ, và môi trường là Linux
Bản thân ngôn ngữ Zig thực sự rất dễ dùng, nhưng tôi thấy compiler và thư viện chuẩn chưa được phát triển đủ theo hướng bảo thủ
Khi bắt đầu với hello world thì có thể bạn chưa gặp vấn đề này, nhưng nếu làm fuzz test hay benchmark thì bạn sẽ muốn chạy binary đã tối ưu hóa
Và rồi việc biên dịch ngay cả một lượng code tương đối nhỏ cũng trở nên quá bực bội
Để so sánh thì tôi nghĩ Zig với tư cách một ngôn ngữ tốt hơn hẳn Rust/C++/C, nhưng trong Rust/C++/C kiểu vấn đề này thực tế hầu như không xảy ra. Với C/C++ thì giả định là dùng clang/gcc/ninja
Trên cùng một máy, tôi có thể cấu hình, build (-O2 hoặc -O3), test một project C++ khoảng 10 nghìn dòng bằng Ninja/Python/clang chỉ trong 200ms
Sẽ rất tuyệt nếu Zig có cơ chế chính thức để xuất Linux library stubs
Khả năng cross-compile và nhắm tới các phiên bản glibc tùy ý của Zig đúng là phép màu thuần túy
Tôi đang tận dụng phép màu này trong một hệ thống build C++ riêng, nhưng để lấy được các library stub đó từ Zig thì phải đi đường vòng
Sẽ tốt hơn nếu nó được cung cấp như một đầu ra chính thức
Rốt cuộc thì có lý do gì để muốn dùng cái này thay vì Node.js và TypeScript?
Nếu bạn không cần vắt kiệt hiệu năng, hay bố trí và kiểm soát bộ nhớ ở mức thấp, thì dùng Zig lại có nhiều điểm bất lợi hơn
CRUD, công việc kiểu “enterprise”, hay website gần như không hưởng lợi gì từ Zig
Một chương trình Zig đã biên dịch có thể chỉ vài KB và không cần dependency
Truy cập mảng viết bằng ngôn ngữ cấp thấp có thể được tối ưu bằng SIMD và song song hóa, và có thể nhanh hơn cùng tác vụ viết bằng JavaScript nhiều bậc độ lớn
Khác biệt này rất lớn trong xử lý văn bản, chỉnh sửa ảnh, xử lý video, hashing, v.v.
Lý do để không dùng JavaScript thì thực tế là vô số