待ちは積み上がる
読了目安 約2分
競プロにない「待ち時間」を逐次コードで体感し、Web の速さが計算ではなく待ちの重ね方で決まることを確かめます。
この章の目次
競プロのプログラムは、入力を読み、計算し、出力して終わります。 時間はほぼ計算量で決まり、CPU はずっと働きっぱなしです。
Web は違います。 処理時間の大半は「データベースの応答待ち」で、その間 CPU は何もせず待っています。
逐次だと待ちが直列に積み上がる
package main
import (
"fmt"
"time"
)
func query(id int) {
time.Sleep(100 * time.Millisecond) // データベースへの問い合わせのつもり
fmt.Printf("問い合わせ %d 完了\n", id)
}
func main() {
start := time.Now()
for i := 1; i <= 5; i++ {
query(i)
}
fmt.Println("所要時間:", time.Since(start).Round(time.Millisecond))
}1 件 100 ミリ秒の待ちが 5 件で、所要時間はおよそ 500 ミリ秒です。 CPU は 500 ミリ秒のうちほとんど遊んでいるのに、待ちを 1 件ずつ順番に消化しているからです。
競プロでは、そもそも非同期の処理を書く場面がほとんどありません。 入力は最初から全部手元にあり、応答を待つ相手がいないからです。 だから上から順に計算する逐次の書き方で何も困りません。
Web では待ちを重ねたい
5 件の待ちを重ねられれば、所要時間は 100 ミリ秒で済みます。 待っている間に次を始める、という動きです。 これは、上から順に実行する逐次のコードでは書けません。
待ちを重ねる道具が goroutine です。
試してみよう
- 件数を 5 から 50 に増やして、所要時間がおよそ 10 倍になることを確かめてください。待ちが積み上がっている証拠です。