【发布时间】:2016-08-12 19:55:17
【问题描述】:
我有一个Get() 函数:
func Get(url string) *Response {
res, err := http.Get(url)
if err != nil {
return &Response{}
}
// res.Body != nil when err == nil
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatalf("ReadAll: %v", err)
}
reflect.TypeOf(body)
return &Response{sync.Mutex(),string(body), res.StatusCode}
}
还有一个Read()函数:
func Read(url string, timeout time.Duration) (res *Response) {
done := make(chan bool)
go func() {
res = Get(url)
done <- true
}()
select { // As soon as either
case <-done: // done is sent on the channel or
case <-time.After(timeout): // timeout
res = &Response{"Gateway timeout\n", 504}
}
return
}
函数返回的Response类型定义为:
type Response struct {
Body string
StatusCode int
}
这个读取函数利用了Get() 函数并且还实现了超时。问题是,如果发生超时并且Get() 响应同时写入res 中的Read(),则可能会发生数据竞争。
我有一个如何解决这个问题的计划。就是使用互斥锁。为此,我将在 Response 结构中添加一个字段:
type Response struct {
mu sync.Mutex
Body string
StatusCode int
}
这样Response 可以被锁定。但是,我不确定如何在代码的其他部分解决此问题。
我的尝试看起来像这样,对于 Get():
func Get(url string) *Response {
res, err := http.Get(url)
if err != nil {
return &Response{}
}
// res.Body != nil when err == nil
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Fatalf("ReadAll: %v", err)
}
reflect.TypeOf(body)
return &Response{sync.Mutex(),string(body), res.StatusCode} // This line is changed.
}
对于Read():
func Read(url string, timeout time.Duration) (res *Response) {
done := make(chan bool)
res = &Response{sync.Mutex()} // this line has been added
go func() {
res = Get(url)
done <- true
}()
select {
case <-done:
case <-time.After(timeout):
res.mu.Lock()
res = &Response{sync.Mutex(), "Gateway timeout\n", 504} // And mutex was added here.
}
defer res.mu.Unlock()
return
}
这个“解决方案”会产生这些错误:
./client.go:54: missing argument to conversion to sync.Mutex: sync.Mutex()
./client.go:63: missing argument to conversion to sync.Mutex: sync.Mutex()
./client.go:63: too few values in struct initializer
./client.go:73: missing argument to conversion to sync.Mutex: sync.Mutex()
./client.go:95: cannot use "Service unavailable\n" (type string) as type sync.Mutex in field value
./client.go:95: cannot use 503 (type int) as type string in field value
./client.go:95: too few values in struct initializer
在这种情况下使用 Mutex 的正确方法是什么?
【问题讨论】:
-
尝试用sync.Mutex替换sync.Mutex(){}
-
这似乎完全错误,甚至比旧代码更生动。不要将互斥锁放在您的结构中,将其保持在读取状态并同步对
res的访问。也许更好:摆脱命名的返回参数并返回来自 Get 的值或您的错误标记。也许更好:将响应从 Get 传输到通过通道读取。 -
对命名返回
res的访问是不同步的,因此很活泼。 -
在 go 例程中写入 res 是不同步的。
-
即使解决了这个问题,这也是让 http 请求超时的错误方法。设置 http
Client.Timeout。您没有提供任何方法来取消正在进行的请求,这可能永远不会释放其资源。
标签: rest http go timeout mutex