我正在编写一个对传入请求进行排队的应用程序。如果请求在队列中停留的时间超过一定时间,我想抛出超时。我正在随着时间的推移而这样做。后:
timeoutCh := time.After(5 * time.Second)
select {
case <-timeoutCh:
//throw timeout 504
case <-processing:
//process request
}
处理通道(连同请求(被放在队列中,当一个请求被取下进行处理时,我向通道发送一个信号来点击 case 语句:
processing <- true
这样做的问题是,如果已经选择了 timeoutCh,处理通道将阻塞,所以我需要一些方法来检查请求是否已超时。
我考虑过使用共享原子布尔值,但是如果我做这样的事情:
case <-timeoutCh:
requestTimedOut = true
然后在发送到处理通道之前检查布尔值,仍然存在争用条件,因为 timeoutCh 情况可能已被选中,但布尔值尚未设置为 true!
在 Go 中是否有处理这种同步问题的惯用方法?
使用数据和超时的互斥体坐标处理。
定义一个类型来保存互斥锁、输入、结果、一个指示工作完成的通道和一个指示工作完成的标志(如果有(。
type work struct {
sync.Mutex
input InputType
result ResultType
signal chan struct {}
done bool
}
请求处理程序创建工作项并将其排队,并等待来自队列处理器的超时或信号。无论哪种方式,请求处理程序都会检查队列处理器是否完成了工作并根据需要做出响应。
func handler(resp http.ResponseWriter, req *http.Request) {
w := &queueElement{
input: computeInputFromRequest(req)
signal: make(chan struct{})
}
enqueue(w)
// Wait for timeout or for queue processor to signal that the work is complete.
select {
case <-time.After(5 * time.Second):
case <-w.signal:
}
w.Lock()
done := w.done // Record state of the work item.
w.done = true // Mark the work item as complete.
w.Unlock()
if !done {
http.Error(w, "Timeout", http.StatusGatewayTimeout)
} else {
respondWithResult(resp, w.result)
}
}
队列处理器将如下所示:
for {
w := dequeue()
w.Lock()
if !w.done {
w.done = true
w.result = computeResultFromInput(w.input)
close(w.signal)
}
w.Unlock()
}
为了确保请求处理程序等待结果,队列处理器在处理工作项时保持锁。