关于并发超时的一点疑问,如何能做到阻塞操作中的超时退出?

panzhongke · 2020-02-23 15:54:24 · 900 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2020-02-23 15:54:24 的主题,其中的信息可能已经有所发展或是发生改变。

func main() {
    select{
        case<-time.After(1*time.Second):
           fmt.Println("timeout")
        default:
           //fmt.Println("doWork")
           time.Sleep(2*time.Second)
           fmt.Println("done")
    }
    fmt.Println("end")
}

运行结果:

doWork
done
end

计划当工作时间过长时,实现超时退出。测试发现,这段逻辑中定时并不能触发提前退出。如何才能实现阻塞调用中的超时退出?谢谢


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

900 次点击  
加入收藏 微博
4 回复  |  直到 2020-02-25 14:08:34
polaris
polaris · #1 · 5年之前

使用 context ,https://studygolang.com/articles/13676

话说作为一个程序员,Markdown 都还不会用吗?

panzhongke
panzhongke · #2 · 5年之前
package main

import (
    "sync"
    "time"
    "fmt"
    "context"
)

func main() {
    var wg sync.WaitGroup
    start:=time.Now()
    ctx,cancel:=context.WithTimeout(context.Background(),2*time.Second)
    defer cancel()
    wg.Add(1)
    go func(){
        defer wg.Done()
        for{
    select {
    case <-time.After(1 * time.Second):
        fmt.Println("overslept")
        return
    case <-ctx.Done():
        fmt.Println(ctx.Err()) // prints "context deadline exceeded"
        return
    default:
        fmt.Println("dowork")
        time.Sleep(3*time.Second)
        fmt.Println("workdone")
        return
    }
    }
    }()
    time.Sleep(1*time.Second)
    cancel()
    wg.Wait()
fmt.Println(time.Since(start))
fmt.Println("end")
}

运行...

dowork
workdone
3.0001716s
end

成功: 进程退出代码 0.

谢谢@polaris回复,我找了个context代码。测试结果还是没有符合预期。感觉根本原因是select是同步循环。对于阻塞没有办法控制。

bbox_230216
bbox_230216 · #3 · 5年之前

你这个原因应该是:time.sleep会阻塞当前协程,没有cpu时间片来执行,所以你上面那个超时控制,也不好使,个人理解

panzhongke
panzhongke · #4 · 5年之前

我也是这样理解,当协程里做了非常耗时或迟迟不能返回的阻塞操作。是没有办法中止的。

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传