<分区>
我喜欢 golang 的一件事是 defer
语句,但是 defer
只适用于 func
范围。
所以,我经常这样使用它
func (s *Something) abc() error {
func() {
s.Lock()
defer s.Unlock()
// don't lock too long
}()
// do something else
if err := func() error {
resp, err := http.Get("https://example.com/api")
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return errors.New("Failed to download")
}
var tmp struct {
Error bool `json:"error"`
Result string `json:"result"`
}
if err := json.NewDecoder(resp.Body).Decode(&tmp); err != nil {
return err
}
if tmp.Error {
return errors.New("API return error")
}
s.somedata = tmp.result
return nil
}(); err != nil {
return err
}
func() {
s.Lock()
defer s.Unlock()
// don't lock too long
}()
// do something else
}
基本上,我将它包装到匿名 block func
中。
这样的用法很常见吗?其他地鼠会滥用这个事实吗?
编辑:澄清
好吧,看来我没解释好, 我想实现两件事
我想实现的是尽可能短的锁定互斥锁
func() { s.Lock() defer s.Unlock() // don't lock too long // there is other code here, this func is not an empty func }()
这个函数里面不止一个http.Get,比方说在调用了example.com/api之后我要调用example.com/api2。我们需要尽快关闭 resp.Body,因此只与该服务器建立一个 TCP 连接。据我所知,如果还有另一个 HTTP 连接尚未关闭(resp.Body.Close() 未在先前的响应中调用),http.Get 将创建另一个 TCP 连接。
编辑 2:更多说明
第一个和最后一个匿名函数和锁是为了同步缓存。我是基于map[string]string实现缓存的,所以需要同步。
我需要先调用example.com/api,根据响应我需要调用example.com/api2或example.com/api3,此时必须关闭之前的http连接,可以是代码像这样
resp, err := http.Get("https://example.com/api")
if err != nil {
return err
}
if resp.StatusCode != 200 {
resp.Body.Close()
return errors.New("Failed to download")
}
// process the body
resp.Body.Close()
但是你需要显式地写两次resp.Body.Close()