在最近關於 Workers 中的 WASI 支援的公告發佈之後,我决定看看用 Zig 編寫程式碼並作為 Worker 執行需要採取哪些步驟,結果發現這件事情特別簡單。這篇貼文記錄了我作為 Zig 的新使用者所採用的過程。看到 Cloudflare Workers 是一個多語言平台,讓人們能夠用自己喜歡的語言或正在學習的語言編寫程式,這真是太令人興奮了!
世界,你好!
無論如何我都算不上一個 Zig 專家,而且老實說,我才剛剛開始研究這種語言,但我們遲早都必須有所行動。所以說,如果我的 Zig 程式碼不夠完美,還請多多包涵。我的目標是用 Zig 建置一個真正的小程式,並將其部署到 Cloudflare Workers 上。然後看看,從一個空白螢幕開始,到寫出實際程式碼,需要多長時間。
我的這個目標也算不上雄心勃勃,只是從 stdin 中讀取一些文字,然後將其列印至 stdout 並加上行號,就像執行 cat -n
一樣。但它確實展示了 Workers 範例有多麼簡單。這個 Zig 程式無論是在我的筆記型電腦的命令列上,還是作為 HTTP API 部署在 Cloudflare Workers 上,效果都是一樣的。
下面就是我的程式碼。它會從 stdin 中讀取一行,然後輸出相同的行並加上行號作為首碼。當不再輸入更多內容時,即會終止。
若要建置 Zig 程式碼,您可以建立一個 build.zig
檔案來定義如何建置專案。對於這個簡單的例子,我選擇從原始碼建置一個可執行檔
const std = @import("std");
pub fn main() anyerror!void {
// setup allocator
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer std.debug.assert(!gpa.deinit());
const allocator = gpa.allocator();
// setup streams
const stdout = std.io.getStdOut().writer();
const in = std.io.getStdIn();
var reader = std.io.bufferedReader(in.reader()).reader();
var counter: u32 = 1;
// read input line by line
while (try reader.readUntilDelimiterOrEofAlloc(allocator, '\n', std.math.maxInt(usize))) |line| {
defer allocator.free(line);
try stdout.print("{d}\t{s}\n", .{counter, line});
counter = counter + 1;
}
}
透過執行 zig build
,編譯器將執行並在 zig-out/bin
下面輸出一個二進位檔
const std = @import("std");
pub fn build(b: *std.build.Builder) void {
const target = b.standardTargetOptions(.{});
const mode = b.standardReleaseOptions();
const exe = b.addExecutable("print-with-line-numbers", "src/main.zig");
exe.setTarget(target);
exe.setBuildMode(mode);
exe.install();
}
WASI
$ zig build
$ ls zig-out/bin
print-with-line-numbers
$ echo "Hello\nWorld" | ./zig-out/bin/print-with-line-numbers
1 Hello
2 World
下一步是讓它在 Workers 上执行,但首先需要將它編譯至具有 WASI 支援的 WASM。
謝天謝地,最新版本的 Zig 提供了開箱即用的功能,因此可以直接告訴編譯器使用 wasm32-wasi
目標建置可執行檔,該目標產生的檔案可以在任何 WASI 相容的 WebAssembly 執行階段上執行,例如 wasmtime。
同一 .wasm 檔案可以在 wasmtime 中執行,並直接部署到 Cloudflare Workers。因此能夠順暢地完成建置、測試及部署。
Workers 上的 Zig
$ zig build -Dtarget=wasm32-wasi
$ ls zig-out/bin
print-with-line-numbers.wasm
$ echo "Hello\nWorld" | wasmtime ./zig-out/bin/print-with-line-numbers.wasm
1 Hello
2 World
在二進位檔準備就緒後,最後一件事是使用 wrangler2 在 Cloudflare Workers 上執行它。這就像在 workers.dev 上發佈 .wasm 檔案一樣簡單。如果您沒有 workers.dev 帳戶,則可以遵循入門指南中的教學課程進行操作,這將幫助您在幾分鐘內完成從編寫程式碼到部署的過程!
事實上,在我注册帳戶後,只需要完成前兩個步驟即可:即安裝 Wrangler 和登入。
然後,我執行了下列命令來發佈 Worker:
$ npx wrangler@wasm login
Attempting to login via OAuth...
Opening a link in your default browser: https://dash.cloudflare.com/oauth2/auth
Successfully logged in.
完成該步驟後,Worker 就可以執行了,我可以透過呼叫從上面的輸出列印的 URL 來叫用它。
$ npx wrangler@wasm publish --name print-with-line-numbers --compatibility-date=2022-07-07 zig-out/bin/print-with-line-numbers.wasm
Uploaded print-with-line-numbers (3.04 sec)
Published print-with-line-numbers (6.28 sec)
print-with-line-numbers.workers.dev
成功了!
echo "Hello\nWorld" | curl https://print-with-line-numbers.workers.dev -X POST --data-binary @-
1 Hello
2 World
結論
這件事對我觸動最大的就是這個過程是多麼簡單而輕鬆。
首先,我針對我的筆記型電腦的架構編譯了一個二進位檔,然後透過向編譯器傳遞一個旗標,將程式碼編譯成了 WebAssembly,最後我讓它在 Workers 上執行**,而無需變更任何程式碼**。
誠然,這個程式並不是太複雜,只需要從 STDIN 中讀取,然後再寫入到 STDOUT 就行了,但這讓我對其潛力充滿信心,尤其是隨著 WASI 等技術的成熟,未來將能夠打造無限可能。