Open5

GoによるWebAPIサーバーと処理性能の高いと噂の実装と比較してみた

NoboNoboNoboNobo

単純に「Hello改行」を返すだけのサーバー。

package main

import (
        "fmt"
        "log"
        "net/http"
)

func greet(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "hello")
}

func main() {
        http.HandleFunc("/hc", greet)
        if err := http.ListenAndServe(":9000", nil); err != nil {
                log.Fatal(err)
        }
}

某言語処理系も11行のシンプルなもの

async fn hc(mut _req: tide::Request<()>) -> tide::Result<String> {
    Ok(format!("hello\n"))
}

#[async_std::main]
async fn main() -> tide::Result<()> {
    let mut app = tide::new();
    app.at("/hc").get(hc);
    app.listen("127.0.0.1:9000").await?;
    Ok(())
}
NoboNoboNoboNobo

Goによる実装のベンチマーク結果

$ go-wrk.exe http://localhost:9000/hc
Running 10s test @ http://localhost:9000/hc
  10 goroutine(s) running concurrently
452697 requests in 9.75366715s, 45.33MB read
Requests/sec:           46413.00
Transfer/sec:           4.65MB
Avg Req Time:           215.456µs
Fastest Request:        0s
Slowest Request:        19.7026ms
Number of Errors:       0
NoboNoboNoboNobo

某言語処理系の(もちろんreleaseビルド)ベンチマーク結果

$ go-wrk.exe http://localhost:9000/hc
Running 10s test @ http://localhost:9000/hc
  10 goroutine(s) running concurrently
271647 requests in 9.71568106s, 26.94MB read
Requests/sec:           27959.65
Transfer/sec:           2.77MB
Avg Req Time:           357.658µs
Fastest Request:        0s
Slowest Request:        337.0013ms
Number of Errors:       0
NoboNoboNoboNobo

一般には某言語処理系の得意なはずのベンチマークなので結果が逆転しているのが興味深いところ。
Windows11上で比較したことが要因なのかなと予想。あとでLinux実装の比較を追記しようと思う。

NoboNoboNoboNobo

しかし某言語処理系、推奨のWebサーバーライブラリがころころ変わっちゃうので毎年試しに書いてみる時に調べなおし&書き直しになっちゃう。せめてサーバーが変化しても実装のほとんどが変わらないようになる仕掛けが欲しいところ。PythonでいうところのWSGI/ASGIみたいな規格があるといいなぁ。

また、これだけシンプルな実装にもかかわらず219ものパッケージのダウンロードとコンパイル処理を行うので最初の確認に時間がかかる・・・(久しぶりに動かすとパッケージインデックスの更新に1分くらい待たされるし)。C++に比べれば楽ちんだしコンパイルもキャッシュが効く分十分快適なんだけどね。Goの「標準かつコンパイルは一瞬」に比べるとこのあたりの重さがどうしても気になってしまう。