iT邦幫忙

2025 iThome 鐵人賽

DAY 12
1
Rust

30 天玩轉 Zenoh:Rust 助力物聯網、機器人與自駕的高速通訊系列 第 12

Day 12: Zenoh 的 非同步 Runtime 抉擇之路

  • 分享至 

  • xImage
  •  

Zenoh 的 非同步 Runtime 抉擇之路

在 Zenoh 的發展過程中,曾經深入比較過幾個 Rust 的非同步框架,其中還經歷了Runtime選擇的轉換async-std -> tokio。

以下筆者先帶各位讀者回顧之前的研究報告
其結果很有意思:async-std 在延遲和吞吐量上表現最好,甚至壓過了 Tokiosmol。特別是在 CPU 密集或網路競爭激烈的情境下,差距就更明顯。


為什麼要做這個測試?

Zenoh 本身就是用 Rust 開發的,目標很明確:
要做到 超低延遲高吞吐量 的通訊能力,非同步框架就是最關鍵的基礎之一。


測試方法

測試方式是透過 ping-pong 應用程式,量測在 localhost 與 100GbE 網路下的往返延遲(RTT)。同時測試 純網路負載 以及 混合計算負載,模擬 Zenoh session 中高達 1000 個並行任務的真實情境。


當年的測試結果

  • async-stdsmol 在不少情境下,都能打平甚至超越標準函式庫。
  • Tokio 的延遲偏高,特別是在 CPU 密集的非同步任務下,往往額外增加 8–10 微秒的延遲。
  • Zenoh 最初打算持續使用 async-std,因為它效能表現最穩定,但團隊也期盼整個 Rust 非同步生態能持續進步。

再次測試

之前的實驗距今已經三年了,套件都早已更新好幾版,究竟最新的測試結果會不會不一樣呢?
以下是筆者更新後的net-benchmark 腳本,並在本機進行了新的網路測試。


測試工具介紹

這套基準工具是一個 統一的 ping-pong 網路測試器,支援多個 Rust 非同步後端(async-stdTokiosmol)以及標準函式庫(std)。它可以量測 TCP/UDP 的往返延遲,並可自由設定封包大小與傳送頻率。

亮點功能:

  • 可選 runtime 後端(--backend tokio|async-std|smol|std
  • 支援 TCP/UDP 的 ping-pong 測試
  • 封包大小、間隔、測試時間都能自訂
  • 支援輸出 CSV 以利分析

Ping 與 Pong 怎麼跑?

  • Pong(接收端)

    • 綁定在某個位址,等待連線
    • 收到資料就馬上回傳
    • 透過選定的 runtime(或標準執行緒)支援多連線
  • Ping(發送端)

    • 主動連線到 pong
    • 定時送出封包並量測 RTT
    • 測試持續到指定時間,然後輸出所有樣本

這樣的設計能精確量測 RTT,並在不同 runtime 框架之間進行公平比較。


使用範例

# 使用 async-std 跑一個 TCP pong 伺服器
cargo run -- --mode pong --protocol tcp --backend async-std --address 127.0.0.1:5555 --size 64

# 使用 async-std 跑一個 TCP ping 客戶端
cargo run -- --mode ping --protocol tcp --backend async-std --address 127.0.0.1:5555 --size 64 --interval 0.001 --duration 10

範例程式碼片段(Tokio 的 TCP Ping)

let now = Instant::now();
stream.write_all(&payload).await.unwrap();
stream.read_exact(&mut payload).await.unwrap();
let elapsed = now.elapsed();
samples.push(elapsed);

這段程式基本展示了 ping 的核心迴圈

  1. 先記錄當前時間
  2. 傳送封包
  3. 收到回傳封包
  4. 記下耗時

同樣的邏輯也套用在所有後端與協定上。


測試結果

以下是 64-byte 封包 的結果:

  • Spec
    • OS: NixOS 25.11.20250905.8eb28ad (Xantusia) x86_64
    • CPU: AMD Ryzen 7 7840U w/ Radeon 780M Graphics (16) @ 5.132GHz

64 bytes 負載的 P50 (中位數) RTT (微秒)

頻率 async-std smol std tokio
10 Hz 340.75 317.84 229.98 296.08
100 Hz 239.11 243.60 238.42 265.34
1 KHz 31.42 31.14 25.43 112.44
10 KHz 22.30 23.77 23.37 36.18
無限 Hz 14.43 14.33 11.00 35.31

comparison

觀察下來:即使在一台普通筆電上,async-std 和 smol 在高頻場景下延遲依然更低;而 Tokio RTT 偏高,跟之前的測試一致。


為什麼 Zenoh 最後選擇了 Tokio?

雖然 async-std 在效能上表現亮眼,但 Zenoh 最終還是轉向 Tokio,原因如下:

  1. 維護性:async-std 已不再維護,長期來說可靠性令人擔憂。
  2. 生態系:Tokio 擁有龐大的函式庫與社群支援,現在幾乎是成了Rust的async runtime不二選擇。
  3. 可客製化:Tokio 允許細緻調整 runtime 行為(像是執行緒數、任務排程、阻塞策略),這在前幾篇文章我們已經深入討論過。
  4. 效能:在低頻情境下,Tokio 的表現其實和其他框架差不多。

上一篇
Day 11: Zenoh 的Runtime - ZRuntime
下一篇
Day 13: Zenoh 如何在 Rust 中用現代 Trait-Based API 統一同步與非同步
系列文
30 天玩轉 Zenoh:Rust 助力物聯網、機器人與自駕的高速通訊19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言