登录
首页 >  Golang >  Go问答

如何正确使用 time.After 进行同步?

来源:stackoverflow

时间:2024-02-28 13:48:23 247浏览 收藏

“纵有疾风来,人生不言弃”,这句话送给正在学习Golang的朋友们,也希望在阅读本文《如何正确使用 time.After 进行同步?》后,能够真的帮助到大家。我也会在后续的文章中,陆续更新Golang相关的技术文章,有好的建议欢迎大家在评论留言,非常感谢!

问题内容

我正在编写一个对传入请求进行排队的应用程序。如果请求在队列中停留的时间超过一定时间,我想抛出超时。我正在花时间这样做。之后:

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()
}

为了确保请求处理程序等待结果,队列处理器在处理工作项时持有锁。

好了,本文到此结束,带大家了解了《如何正确使用 time.After 进行同步?》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多Golang知识!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>