让我们假设以下代码
type resultWrapper struct {
result Result
err error
}
func (e executor) Execute(ctx context.Context) Result {
ch := make(chan ResultWrapper, 1)
go func() {
defer close(ch)
// base also returns type Result
res := e.base.Execute(ctx)
if res.IsError() {
ch <- resultWrapper{
result: &e.defaultResponse,
err: nil,
}
return
}
ch <- wrapper{
result: &res,
err: nil,
}
}()
select {
case <-time.After(e.timeout):
return e.defaultResponse
case res := <-ch:
return res.result
}
}
我的问题是我是否应该以某种适当的方式关闭由time.After
通道创建的通道?我不完全理解如果我超时退出主Execute
函数,goroutine调用e.base.Execute
会发生什么?
2条答案
按热度按时间vdgimpew1#
time.After()
返回一个只接收通道:不能关闭,引用自规格:内置功能:关闭:
如果参数
ch
的核心类型为channel,则内置函数close
会记录不再在该channel上发送值。如果ch
是只接收通道,则会出错。time.After()
的文档还指出:在计时器触发之前,垃圾回收器不会恢复基础计时器。如果需要提高效率,请改用NewTimer并调用Timer。如果不再需要计时器,请停止。
因此,您可以使用
time.NewTimer()
,之前您可以使用Timer.Stop()
“释放”它。**但是!**由于您调用的操作
e.base.Execute(ctx)
已经支持上下文,因此最简单的解决方案是创建一个新的、带超时的派生上下文(使用context.WithTimeout()
):如果
e.base.Execute()
正确实现,它必须监视传递的上下文,这将在e.timeout
之后被取消。注意延迟的cancel()
调用,如果e.base.Execute()
在e.timeout
之前完成,它将释放已使用的资源。1l5u6lss2#
不幸的是,你不能停止
time.After
的goroutine,如果你担心泄露长期存在的例程,最好使用time.timer,它可以被停止。