golang 的 deadline/timeout(超时) 弹性模式。
创建 deadline 只需一个参数:等待的时间。
💡 前几天发布后,发现末尾的地方,写得不是很清楚,于是删掉了,今天补充后,重新进行发布
仓库给的使用例子:
1 | go复制代码dl := deadline.New(1 * time.Second) |
首先通过 New 函数,新建一个超时器,传入的参数,是所期待的超时时长
1 | go复制代码func New(timeout time.Duration) *Deadline { |
然后调用超时器的 Run 方法即可,在运行时间超出所期待的超时时长就会退出,返回 ErrTimedOut
的错误
1 | go复制代码// ErrTimedOut is the error returned from Run when the deadline expires. |
测试用例所要执行的 work 函数定义:
1 | go复制代码func takesFiveMillis(stopper <-chan struct{}) error { |
可以看出我们要执行的函数的参数都必须是 chan 类型,然后定义的字段名是 stopper,其实定义为其他字段名也是一样的
如果只是想简单地将我们执行的函数超时就不执行了,那么直接定义完相应的执行函数和新建超时器进行执行即可,比如:
1 | go复制代码func takesFiveMillis(stopper <-chan struct{}) error { |
但是如果你想在超时后执行一些操作,那么就可以利用我们执行函数的传入 stopper 参数,比如:
1 | go复制代码dl := New(10 * time.Millisecond) |
这里有一个大家可能会很疑惑的点,就是超时之后,Run 函数不应该是立即退出了吗?其实是的,超时之后就立即退出了,但是我们的 work 函数执行的时候是用协程去执行的,所以我们的 work 还是在执行中,
所以就需要 done 通道,去判断 work 函数是否执行完了,否则这个测试用例就直接退出了, 为了我这里说的是否正常,我们将测试用例注释相应的改动:
查看执行结果后,可以看出我这里所说的是正确的
这里大家可能还有一个疑惑点,就是我们这里的 stopper 阻塞在这里,那么超时之后,不是就进行关闭了吗?
这里就设计到 channel 的知识点了,读已经关闭的 channel 进行读操作的时候,依然是可以读的,我们这里的 stopper 是无缓冲区的 channel,那么读出来的就是相应类型的零值,但是如果是有缓存区的呢?如果关闭前,有缓存区的 channel 里面有数据,我们仍然能读出来,读到没有数据的时候,再读就是相应类型的零值。
这里我们引申一下,如果去写已经关闭的缓存区呢?这种情况就会 panic:send on closed channel 的情况,对于有无缓冲区的 channel 都是一样的结果
本文转载自: 掘金