go - 使用上下文在连续的函数调用之间共享一个公共超时
问题描述
我想在 Go 程序中进行一些连续的函数调用,例如
(显然省略了错误检查)
result1, err := fxn1()
result2, err := fxn2()
我希望整个调用序列在一定时间内完成,否则应该中止该过程(并且程序退出错误)
假设我有超时(作为持续时间)以某种方式传递到我的程序中,我想一种方法是
a)创建一个带有截止日期的上下文,将超时添加到当前时间
myDeadline := time.Now().Add(timeout * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), myDeadline)
defer cancel()
b)让最终函数通过通道传达其结果(我认为这称为通道生成器模式?)
func fxn2() (chan string) {
resChan := make(chan string)
go func() {
// get the job done
resChan <- result
}()
return resChan
}
和
c ) 然后在 select 语句上阻塞主 goroutine,如下所示
select {
case err := <-ctx.Done():
log.Println("Process has timed out...exiting")
os.Exit(err)
case result := <- resChan
log.Println("Process completed in time")
}
这是我现在能想到的最好的方法,但我在徘徊是否有更好或更惯用的方式(比如为每个函数生成新的上下文副本 - 当然应该接受context.Context
作为输入参数)以某种方式跟踪剩余时间?)
解决方案
这比它需要的要复杂得多。有两种方法可以做到这一点:
如果函数带
context.Context
参数,则无需<-ctx.Done()
在顶层等待。相反,当上下文完成时,函数将(在一些未知的未知延迟之后,可能永远不会,取决于函数)返回ctx.Err()
(应该是context.DeadlineExceeded
)。如果函数不带
context.Context
参数,那么您可以退出该过程。你不需context.Context
要这样做。我的意思是,这context.Context
只是一种更复杂的调用方式<-time.After(timeout)
。
type myResultType struct{}
func longFunctionCall() (*myResultType, error) {
...
}
func invokeFunctionWithDeadline() {
const timeout = 10 * time.Second
// Run the function on a goroutine, and return the result with a channel.
type resultStruct struct {
value *myResultType
err error
}
ch := make(chan resultStruct)
go func() {
v, err := longFunctionCall()
ch <- resultStruct{v, err}
}()
// Wait for either the timeout, or the result.
select {
case <-time.After(timeout):
log.Println("Timed out")
os.Exit(1)
case result := <-ch:
log.Println("Success:", result)
}
}
请注意,此策略仅在您调用 时才有效os.Exit()
,这会强制终止所有未完成的 goroutine。
推荐阅读
- jenkins - Jenkins 构建频率基于之前的构建状态
- arrays - 我在消息框中显示我的数组的输出时遇到问题
- sql - 与表格列表相比,MS Access 从长文本字段中提取多个匹配的文本字符串
- gpu - 如何在 GPU 上获取包含数据的卤化物缓冲区?
- angular - firebase.auth.Auth.signInWithCredential 已弃用。请改用 firebase.auth.Auth.signInAndRetrieveDataWithCredential
- java - 通过套接字发送numpy数组并在java中检索它
- laravel - laravel 路由参数在 unittest 上返回 null
- c# - Visual Studio 2017 为我的多平台 xamarin 应用报告此错误
- mysql - AWS 上的 MYSQL 或 PostgresSQL
- c - 如何使用位移/屏蔽将二进制转换为十六进制