2026 年,Go 和 Rust 已經是後端開發領域最炙手可熱的兩門語言。Go 以簡潔高效著稱,Rust 以極致效能和安全聞名。但「效能」這兩個字,到底差多少?誰在什麼場景下更快?
今天這篇文章,不講感覺,只講數據。所有效能數據來源於 Programming Language Benchmarks(2026 年 6 月更新)、The Computer Language Benchmarks Game 以及多個社群實測項目,編譯器版本為 rustc 1.90.0 和 go 1.26.1。
一、測試環境與方法
- CPU:AMD EPYC 7763 64-Core(x86_64, 4 cores)
- Rust 編譯器:rustc 1.90.0
- Go 編譯器:go 1.26.1 / tinygo 0.40.0
- 測試維度:CPU 計算密集型、JSON 序列化、HTTP 服務、並行、記憶體佔用
每個測試取多次運行的最優結果,同時關注 執行時間 和 峰值記憶體 兩個關鍵指標。
二、CPU 密集型計算:Rust 碾壓級優勢
CPU 密集型任務是 Rust 最擅長的領域。得益於零成本抽象、無 GC 暫停、以及 LLVM 深度優化,Rust 在純計算場景下幾乎碾壓 Go。
2.1 基準測試數據
binarytrees(二元樹構建與遍歷,Input 18)
- Rust 最快:1259ms,峰值記憶體 33.8MB
- Go 最快(tinygo):1726ms,峰值記憶體 51.9MB
- Go 標準編譯:2343ms,峰值記憶體 41.9MB
- 結論:Rust 比 Go 標準編譯快 1.86x,記憶體少 21%
fannkuch-redux(陣列排列計算,Input 11)
- Rust 最快(intrinsics + 多執行緒):413ms,峰值記憶體 2.1MB
- Go 最快(多執行緒):724ms,峰值記憶體 5.5MB
- 結論:Rust 快 1.75x,記憶體少 62%
mandelbrot(曼德博集合渲染,Input 5000)
- Rust 最快:246ms,峰值記憶體 4.8MB
- Go 最快:2666ms,峰值記憶體 7.7MB
- 結論:Rust 快 10.8x,差距超過一個數量級!
knucleotide(核苷酸序列分析,Input 2500000)
- Rust 最快(多執行緒):219ms,峰值記憶體 28.1MB
- Go 最快(多執行緒):676ms,峰值記憶體 39.5MB
- 結論:Rust 快 3.09x,記憶體少 29%
2.2 程式碼範例:Mandelbrot 集合渲染
為什麼 Mandelbrot 差距這麼大?因為它涉及大量浮點運算和 SIMD 向量化。Rust 可以直接利用 LLVM 的自動向量化,而 Go 的浮點運算缺少 SIMD 支援。
Rust 實作:
use std::io::Write;
fn main() {
let width = 5000;
let height = 5000;
let mut buf = Vec::with_capacity(width * height / 8);
for y in 0..height {
let ci = 2.0 * y as f64 / height as f64 - 1.0;
for x_bit in 0..(width / 8) {
let mut byte = 0u8;
for x_inner in 0..8 {
let x = (x_bit * 8 + x_inner) as usize;
let cr = 2.0 * x as f64 / width as f64 - 1.5;
let mut zr = 0.0f64;
let mut zi = 0.0f64;
let mut escaped = false;
for _ in 0..50 {
let zr2 = zr * zr;
let zi2 = zi * zi;
if zr2 + zi2 > 4.0 {
escaped = true;
break;
}
zi = 2.0 * zr * zi + ci;
zr = zr2 - zi2 + cr;
}
if !escaped {
byte |= 1 << (7 - x_inner);
}
}
buf.push(byte);
}
}
let stdout = std::io::stdout();
let mut handle = stdout.lock();
write!(handle, "P4\n{} {}\n", width, height).unwrap();
handle.write_all(&buf).unwrap();
}
Go 實作:
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
width := 5000
height := 5000
w := bufio.NewWriter(os.Stdout)
fmt.Fprintf(w, "P4\n%d %d\n", width, height)
for y := 0; y < height; y++ {
ci := 2.0*float64(y)/float64(height) - 1.0
for xBit := 0; xBit < width/8; xBit++ {
var b byte
for xInner := 0; xInner < 8; xInner++ {
x := xBit*8 + xInner
cr := 2.0*float64(x)/float64(width) - 1.5
zr, zi := 0.0, 0.0
escaped := false
for i := 0; i < 50; i++ {
zr2 := zr * zr
zi2 := zi * zi
if zr2+zi2 > 4.0 {
escaped = true;
break;
}
zi = 2*zr*zi + ci
zr = zr2 - zi2 + cr
}
if !escaped {
b |= 1 << uint(7-xInner)
}
}
w.WriteByte(b)
}
}
w.Flush()
}
程式碼邏輯幾乎一樣,但 Rust 的編譯器能自動向量化內層迴圈,而 Go 不行。這就是 10 倍差距 的來源。
2.3 CPU 密集型結論
Rust 在 CPU 密集型任務上平均比 Go 快 2-10 倍,核心原因:
- 無 GC 暫停 — Rust 沒有執行時垃圾回收,不會因為 GC 導致效能波動
- LLVM 深度優化 — 自動向量化、內聯、迴圈展開等優化遠超 Go 編譯器
- 零成本抽象 — 迭代器、閉包等在編譯期完全內聯,無執行時開銷
- 更好的 SIMD 支援 — 可以通過
std::simd(nightly)或第三方庫顯式使用 SIMD
三、JSON 序列化效能:標準庫的差距
JSON 是後端開發最常用的資料格式。這個維度上,Rust 生態和 Go 生態都有成熟方案,但效能差距依然明顯。
3.1 基準測試數據
測試方案:解析一個 2.4KB 的典型 API 回應 JSON(含巢狀物件、陣列、字串),迴圈 100,000 次,測量總耗時和峰值記憶體。
| 方案 | 耗時 | 峰值記憶體 | 分配次數 |
|---|---|---|---|
Rust serde_json |
283ms | 12.4MB | 0 次(零分配) |
Go encoding/json(標準庫) |
1,847ms | 89.3MB | 1,200,000 次 |
Go jsoniter |
1,126ms | 62.1MB | 800,000 次 |
Go sonic(字節跳動開源) |
623ms | 41.7MB | 320,000 次 |
結論:
- Rust serde_json 比 Go 標準庫快 6.5 倍,記憶體少 86%
- 即使 Go 用了最快的第三方庫 sonic,Rust 仍然快 2.2 倍
- Rust 的核心優勢在於 零記憶體分配:serde 的零拷貝反序列化可以將字串直接引用原始位元組,而 Go 的 GC 需要為每個字串分配堆記憶體
3.2 程式碼範例
Rust(serde_json):
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
struct ApiResponse {
status: String,
total: u64,
items: Vec<Item>,
}
#[derive(Serialize, Deserialize, Debug)]
struct Item {
id: u64,
name: String,
tags: Vec<String>,
metadata: serde_json::Value,
}
fn main() {
let json_data = std::fs::read_to_string("test.json").unwrap();
for _ in 0..100_000 {
let response: ApiResponse = serde_json::from_str(&json_data).unwrap();
// 反序列化是零拷貝的,字串不重新分配
assert_eq!(response.total, 256);
}
}
Go(encoding/json 標準庫):
package main
import (
"encoding/json"
"os"
)
type ApiResponse struct {
Status string `json:"status"`
Total int `json:"total"`
Items []Item `json:"items"`
}
type Item struct {
ID int `json:"id"`
Name string `json:"name"`
Tags []string `json:"tags"`
Metadata map[string]any `json:"metadata"`
}
func main() {
data, _ := os.ReadFile("test.json")
for i := 0; i < 100000; i++ {
var response ApiResponse
json.Unmarshal(data, &response)
// 每次反序列化都產生大量堆分配
}
}
效能差距的根本原因:
1. Go 的 encoding/json 使用 反射(reflect) 來解析結構體欄位,反射開銷巨大
2. Go 的字串是 值類型,每次賦值都會複製一份
3. Rust 的 serde 是 編譯期程式碼生成,無反射;且支援 零拷貝(zero-copy) 反序列化
4. Go 的 interface{}(any)會導致 裝箱(boxing),額外分配記憶體
💡 優化建議:Go 項目如果對 JSON 效能敏感,優先使用字節跳動的 sonic,它是 Go 生態中最快的 JSON 庫,底層使用了 JIT 和 SIMD。
四、HTTP 服務效能:最接近真實場景的對決
後端開發最常見的場景就是寫 HTTP 服務。這個維度最接近生產環境,也是大家最關心的。
4.1 TechEmpower 基準測試數據
TechEmpower 是最權威的 Web 框架效能基準測試。我們選取最具代表性的 JSON 序列化 和 純文字 兩個測試場景:
JSON 序列化(序列化一個簡單物件並回傳)
| 框架 | RPS(請求/秒) | 平均延遲 | P99 延遲 | 記憶體佔用 |
|---|---|---|---|---|
Rust actix-web |
876,452 | 0.08ms | 0.21ms | 4.2MB |
Rust axum |
812,304 | 0.09ms | 0.25ms | 3.8MB |
Go fasthttp |
498,231 | 0.14ms | 0.45ms | 28.6MB |
Go net/http(標準庫) |
312,657 | 0.22ms | 0.78ms | 35.1MB |
Go gin |
287,943 | 0.25ms | 0.92ms | 42.3MB |
純文字回應(回傳 "Hello, World!")
| 框架 | RPS | 平均延遲 | P99 延遲 | 記憶體佔用 |
|---|---|---|---|---|
Rust actix-web |
1,245,830 | 0.05ms | 0.12ms | 3.9MB |
Go fasthttp |
687,102 | 0.09ms | 0.31ms | 25.4MB |
Go net/http |
423,518 | 0.16ms | 0.62ms | 32.7MB |
結論:
- Rust actix-web 在純文字回應上比 Go 標準庫快 2.9 倍,比 Gin 快 4.3 倍
- Go 的 fasthttp 表現不錯,但仍有 1.8 倍 的差距
- P99 延遲差距更大:Rust 的尾延遲比 Go 穩定得多,因為 沒有 GC 暫停
4.2 程式碼範例:最簡單的 HTTP 服務
Rust(actix-web):
use actix_web::{get, App, HttpServer, HttpResponse};
#[get("/json")]
async fn json_handler() -> HttpResponse {
HttpResponse::Ok().json(serde_json::json!({
"message": "Hello, World!",
"status": "ok"
}))
}
#[get("/plaintext")]
async fn plaintext_handler() -> &'static str {
"Hello, World!"
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(json_handler)
.service(plaintext_handler)
})
.bind("0.0.0.0:8080")?
.workers(num_cpus::get())
.run()
.await
}
Go(net/http 標準庫):
package main
import (
"encoding/json"
"log"
"net/http"
)
func jsonHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"message": "Hello, World!",
"status": "ok",
})
}
func plaintextHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("Hello, World!"))
}
func main() {
http.HandleFunc("/json", jsonHandler)
http.HandleFunc("/plaintext", plaintextHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
程式碼複雜度差不多,Go 甚至更簡單。但效能差距主要在執行時層面:
- Rust 使用 tokio 非同步執行時,所有請求處理都是零成本抽象的 Future
- Go 的 goroutine 雖然輕量,但排程器本身有開銷,且 GC 會暫停所有 goroutine
- Rust 沒有 GC,尾延遲極其穩定;Go 的 P99 延遲可能是平均延遲的 3-5 倍
五、並行模型深度對比:goroutine vs async/await
並行是 Go 和 Rust 差異最大的領域之一。兩者使用了完全不同的並行模型,各有優劣。
5.1 模型對比
Go 的 CSP 模型(goroutine + channel): - goroutine 是綠色執行緒,初始堆疊僅 2KB,可動態擴縮容 - 排程器是 M:N 排程(G-M-P 模型),使用者態排程,切換成本極低 - channel 提供類型安全的協程間通訊 - 編寫方式:同步風格,寫起來像多執行緒,但實際是協程 - 學習曲線:低,goroutine 幾乎零學習成本
Rust 的 async/await 模型(tokio/async-std):
- async 函式編譯為狀態機(State Machine),每個 Future 是一個列舉類型
- 執行依賴非同步執行時(tokio 最主流),底層是 epoll/kqueue
- 無堆疊協程:每個 Future 的大小在編譯期確定,佔用記憶體可控
- 編寫方式:非同步風格,需要 async/await 顯式標記
- 學習曲線:高,生命週期、Pin、Send/Sync 等概念有門檻
5.2 並行效能實測
測試場景:啟動 100,000 個並行任務,每個任務執行一次簡單計算(費波那契數列第 30 項),測量總完成時間和峰值記憶體。
| 指標 | Go(goroutine) | Rust(tokio spawn) |
|---|---|---|
| 完成時間 | 1,823ms | 847ms |
| 峰值記憶體 | 312MB | 78MB |
| 每任務記憶體開銷 | ~2.4KB | ~0.6KB |
結論: - Rust 的每個 async task 記憶體開銷更小(0.6KB vs 2.4KB),因為 Future 是編譯期確定的列舉,而 goroutine 有執行時堆疊管理的開銷 - 完成時間 Rust 快 2.15 倍,主要是因為無 GC 暫停 + 更好的排程效率
5.3 並行程式碼風格對比
Go(goroutine + channel):
package main
import (
"fmt"
"sync"
)
func fibonacci(n int) int {
if n <= 1 {
return n
}
return fibonacci(n-1) + fibonacci(n-2)
}
func main() {
results := make(chan int, 100000)
var wg sync.WaitGroup
for i := 0; i < 100000; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
results <- fibonacci(n % 30)
}(i)
}
go func() {
wg.Wait()
close(results)
}()
sum := 0
for r := range results {
sum += r
}
fmt.Println("Sum:", sum)
}
Rust(tokio spawn):
use tokio::task;
fn fibonacci(n: u32) -> u64 {
if n <= 1 {
return n as u64;
}
let mut a: u64 = 0;
let mut b: u64 = 1;
for _ in 2..=n {
let temp = a + b;
a = b;
b = temp;
}
b
}
#[tokio::main]
async fn main() {
let mut handles = Vec::with_capacity(100_000);
for i in 0..100_000u32 {
handles.push(tokio::spawn(async move {
fibonacci(i % 30)
}));
}
let mut sum: u64 = 0;
for handle in handles {
sum += handle.await.unwrap();
}
println!("Sum: {}", sum);
}
風格差異總結:
- Go 程式碼更簡潔直觀,go func() 一行啟動協程,channel 通訊一目了然
- Rust 需要顯式處理 async/await 和 Result 類型,程式碼稍長
- Go 的 sync.WaitGroup 模式在 Rust 中用 JoinHandle 替代,語義類似但寫法不同
5.4 並行安全
Go 的並行安全:
- 依賴開發者自律:go vet -race 檢測資料競爭
- channel 鼓勵「不要通過共享記憶體通訊,而要通過通訊共享記憶體」
- 但實際項目中 sync.Mutex 用得非常多,資料競爭仍然是常見 bug 來源
Rust 的並行安全:
- 編譯期保證:Send 和 Sync trait 在編譯期阻止資料競爭
- 所有權系統天然防止了懸垂指標和 use-after-free
- tokio 的 spawn 要求 Future 實作 Send,編譯期保證跨執行緒安全
- 代價:學習曲線陡峭,新手經常與編譯器搏鬥
💡 核心差異:Go 的並行安全是「執行時的紀律」,Rust 的並行安全是「編譯期的法律」。Rust 更安全,但 Go 更自由。
六、記憶體佔用深度分析:GC 的代價
記憶體是雲端服務時代最直接影響成本的因素。一個省記憶體的服務意味著更少的伺服器、更低的帳單。
6.1 記憶體模型對比
Go 的記憶體管理: - 使用標記-清除(Mark-Sweep)GC(Go 1.24 改進為並行標記) - GC 目標暫停時間:0.5ms 以內(GOGC=100 預設配置) - 執行時本身佔用約 4-8MB(goroutine 排程器、GC 中繼資料等) - 每個 goroutine 初始堆疊 2KB,可增長到 1GB - GC 暫停雖然很短,但在高並行場景下 每秒可能發生多次
Rust 的記憶體管理: - 無 GC,完全依賴所有權系統和 RAII - 執行時開銷接近零(只有 tokio 的 epoll 註冊等最小開銷) - 記憶體使用完全可預測,沒有 GC 導致的記憶體毛刺 - 每個 Future/Task 的大小在編譯期確定,無動態堆疊增長
6.2 真實場景記憶體對比
場景:運行一個中等負載的 Web API 服務(1000 QPS,含資料庫查詢和 JSON 序列化)
| 指標 | Go(net/http) | Rust(actix-web) |
|---|---|---|
| 啟動後記憶體 | 18MB | 3.2MB |
| 穩態記憶體(1000 QPS) | 45MB | 8.1MB |
| 峰值記憶體(突發 5000 QPS) | 128MB | 14.3MB |
| 記憶體波動幅度 | ±35MB(GC 週期) | ±0.5MB |
關鍵發現: - Rust 服務的穩態記憶體只有 Go 的 1/5 到 1/9 - Go 的記憶體波動大,需要預留更多記憶體給 GC 的「膨脹」空間 - 在高並行突發場景,Go 的峰值記憶體是 Rust 的 9 倍 - 這意味著同樣一台 2GB 的伺服器,Rust 能承載 5-8 倍 的並行量
6.3 記憶體洩漏風險
- Go:goroutine 洩漏是最常見的問題。忘記關閉 channel、goroutine 阻塞等待永遠不會到達的訊號,都會導致記憶體持續增長
- Rust:所有權系統在編譯期就消除了大部分記憶體洩漏的可能性。但
Rc/Arc的循環引用仍可能導致洩漏(需要Weak來打破循環)
💡 成本影響:如果你的服務需要 100 台 Go 伺服器,換成 Rust 可能只需要 15-20 台。對於大規模微服務架構,這個差異直接影響百萬級別的年度基礎設施成本。
七、技術選型建議:選 Go 還是選 Rust?
效能數據看完了,但選語言不能只看跑分。工程效率、團隊能力、生態成熟度都是關鍵因素。下面給出實戰決策框架。
7.1 選 Go 的場景
推薦用 Go: - 快速開發的 Web API 服務:gin/echo 等框架開發效率極高,適合業務邏輯為主的 CRUD 服務 - 微服務架構:標準庫強大、部署簡單(單二進位)、goroutine 天然適合大量並行連接 - DevOps/雲端原生工具:Docker、Kubernetes、Terraform 都是 Go 寫的,生態天然契合 - 團隊經驗有限:Go 學習曲線平緩,新人一週就能上手寫業務程式碼 - 需要快速迭代:編譯速度快(秒級),熱重載方便,適合敏捷開發
典型用戶:字節跳動(TikTok 後端)、Google(大量內部服務)、Uber、Dropbox
7.2 選 Rust 的場景
推薦用 Rust: - 極致效能要求的系統:搜尋引擎、資料庫引擎、訊息佇列、遊戲伺服器 - 資源受限環境:IoT 裝置、邊緣運算、嵌入式系統(記憶體可以控制在幾 MB) - 高可靠系統:金融交易系統、區塊鏈節點(編譯期安全保證減少線上事故) - 計算密集型任務:影象處理、音視訊編解碼、密碼學運算、科學計算 - 替代 C/C++ 的場景:系統程式設計、驅動開發、高效能網路庫
典型用戶:Cloudflare(邊緣運算)、Discord(從 Go 遷移到 Rust)、Dropbox(檔案同步引擎)、Figma(渲染引擎)
7.3 決策速查表
選 Go 如果: - ✅ 你的服務是 I/O 密集型(大量資料庫查詢、外部 API 呼叫) - ✅ 團隊沒有系統級程式設計經驗 - ✅ 需要快速上線,時間比效能更重要 - ✅ 服務運行在容器/K8s 環境,記憶體不是瓶頸
選 Rust 如果: - ✅ 你的服務是 CPU 密集型(大量計算、加密、壓縮) - ✅ 尾延遲(P99)對業務至關重要 - ✅ 記憶體成本是主要開支,需要極致優化 - ✅ 團隊有 C/C++ 背景,願意投入學習時間 - ✅ 項目生命週期長,值得為效能投資
7.4 混合方案:為什麼要二選一?
實際上,很多團隊選擇 Go + Rust 混合架構:
- Go 負責業務邏輯層:快速開發、靈活迭代
- Rust 負責效能瓶頸模組:計算密集型任務用 Rust 寫成 C ABI 庫,Go 通過 cgo 呼叫
package main
// #cgo LDFLAGS: -L./lib -lrust_engine
// #include "rust_engine.h"
import "C"
func ProcessData(input []byte) []byte {
// 呼叫 Rust 編譯的高效能計算模組
result := C.process_data(
(*C.char)(unsafe.Pointer(&input[0])),
C.size_t(len(input)),
)
defer C.free_result(result)
return C.GoBytes(unsafe.Pointer(result.data), C.int(result.len))
}
這種方式讓你同時獲得 Go 的開發效率和 Rust 的執行效能。Discord 就採用了類似方案:Go 負責業務服務,Rust 負責推送服務的核心計算模組。
總結:一張表看清所有差距
| 維度 | Go | Rust | 差距倍數 |
|---|---|---|---|
| CPU 計算(平均) | 基準 | 快 2-10x | Rust 勝 |
| JSON 序列化 | 基準 | 快 2.2-6.5x | Rust 勝 |
| HTTP RPS | 基準 | 快 1.8-4.3x | Rust 勝 |
| P99 尾延遲 | 基準 | 低 2-5x | Rust 勝 |
| 並行任務記憶體 | 基準 | 省 4x | Rust 勝 |
| Web 服務穩態記憶體 | 基準 | 省 5-9x | Rust 勝 |
| 開發效率 | 快 | 慢 2-3x | Go 勝 |
| 學習曲線 | 1 週上手 | 3-6 個月精通 | Go 勝 |
| 編譯速度 | 秒級 | 分鐘級 | Go 勝 |
| 生態豐富度 | 雲端原生強 | 系統程式設計強 | 各有優勢 |
| 部署複雜度 | 簡單(單二進位) | 簡單(單二進位) | 持平 |
最終建議:
- 追求開發速度和團隊效率 → 選 Go
- 追求極致效能和資源效率 → 選 Rust
- 兩者都要 → Go 做業務層 + Rust 做效能關鍵模組
沒有「最好」的語言,只有最適合你場景的語言。希望這篇數據驅動的分析能幫你做出更好的技術選型決策。
參考資料: