今天在 Github 上闲逛的时候,看到 mattn 大大的新 repo : go-drainclose

一看 README ,我勒个乖乖:

Make your app 4x faster.

真真是刁刁的样子啊。

先看看用法:

1
2
3
4
5
6
7
resp, err := http.Get(blah)
if err != nil {
return err
}
//defer resp.Body.Close()
defer drainclose.Close(resp.Body)
json.NewDecoder(resp.Body).Decode(&data)

只要把以前的 defer resp.Body.Close() 替换掉就好了,真是简单易用。

那么黑魔法是怎么完成的呢? mattn 大大只丢下一句话:

See https://github.com/google/go-github/pull/317

好吧,那就看看这个 PR ,大概就是像下面这样

1
2
3
4
5
6
//defer resp.Body.Close()
defer func() {
// Drain and close the body to let the Transport reuse the connection
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
}()

Magic!
代码的意思就是复用 TCP/TLS 连接来达到更高更快更强的目的啦。

当然啦,这样做的坏处也是有的,就是要实现连接的复用的话,那么就必须把前一个连接的内容全部读完才能复用(就算你没有读取resp.Body),所以如果前一个连接的 Body 比较大而又不想读取里面的内容的话,就不要用黑魔法啦。

附上大神的实现代码:

1
2
3
4
5
6
7
8
9
func Close(body io.ReadCloser) error {
if body == nil {
return nil
}
if _, err := io.Copy(ioutil.Discard, body); err != nil {
return err
}
return body.Close()
}

就是在上面那个PR的基础上加入了判空和错误处理。