I think I just made go-github 4x faster in 4 lines of code (and 4hrs). Always make sure you are reusing connections! https://t.co/ORCv1a4prv
— Filippo Valsorda (@FiloSottile) March 27, 2016
go-github という、Google が開発している GitHub API ライブラリがあるのですが、今回 filosottile さんがたった4行のコードで実行速度を4倍にするという pull-request を書きました。
いったいどういう事かというと、golang の json.Decoder
を使って http.Response.Body
から JSON を読み取ると最後の改行(EOF)が読み込まれずに残ってしまい、レスポンスを完全に読み切らないまま http.Response.Body.Close()
が呼ばれてしまう。これはこれで別に問題のあるコードではないのですが、継続してリクエストを送る場合にレスポンスを完全に読み切っていなかった事でクライアントは物理切断してしまい TLS 接続が再利用されなくなります。この TLS 接続を再利用する為には残りのたった1バイトを読み捨ててあげる必要がある。そこで
defer func() {
// Drain and close the body to let the Transport reuse the connection
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}()
というコードになったという事です。個人的にはこれは golang 本体がやるべき仕事な気もするのでオススメはしませんし、今後 golang に何かしらの対応が入るのかもしれませんが、今すぐ高速な HTTP 通信が必要という方は試してみるのも良いかもしれません。
ちなみにこの件、Content-Length 分読み取って json.Unmarshal
していれば発生しないはずですが json.Decoder
のメモリを極力使わないというメリットが使えなくなるというのもあり一長一短ですね。