在Golang中,我对将contexts
下游传递给其他方法和函数的意图相当陌生。我了解context
如何运作,如何使用,如何保持其价值,如何与父context
及其行为相关 - 我只是不明白为什么首先使用上下文。
在一个更具体的例子中,这是这个问题的实际原因,在我工作的公司中,我们已经确定了一些由于边缘情况而经常发生的长时间运行的查询。
我们决定采取一个明显的解决方案,考虑到我们的限制,直到我们花时间来解决根本原因,就是杀死超过5分钟的查询。
运行我们的事务的方法接受最初在API调用中启动的context
。这个context
一直传递给事务函数。那一刻,我找到了两个解决方案来解决这个问题:
1)使用新的上下文:
发起新的context.WithTimeout(ctx, time.Duration( 5 * time.Minute) )
观看Done
中的go routine
频道,并在有信号时终止该交易
cancel
上下文并按预期提交事务。 2)使用Timer
:
Timer
从逻辑上讲,它们是同一个解决方案,但是,何时以及如何决定是否使用context
设置截止日期或旧的Timer
?
答案 0 :(得分:3)
答案在于context.Context
和time.Timer
如何传递(取消)信号。
context.Context
可让您通过Context.Done()
方法访问频道,当使用它的goroutines终止时,该方法将被关闭。
time.Timer
可让您在给定时间段后访问Timer.C
结构字段中将要发送值的频道(该值将是当前时间) ,但这里不重要。)
在那里,重点突出。可以通过任意数量的goroutine观察到通道关闭,并且无限次。 Spec: Receive operator:
closed频道上的接收操作始终可以立即进行,在收到任何先前发送的值后,会产生元素类型zero value。
因此Context
可用于表示取消任意数量的goroutine和地点。 Timer
只能用于发信号通知一个目标,即从其频道接收值的目标。如果有多个客户正在收听或试图从其频道收到,只有一个会幸运地收到它。
此外,如果您正在使用/使用已经支持/期望context.Context
的代码,那么问题不是一个问题。 Go 1.8还添加了more context support。 significant additions包中有database/sql
个上下文支持;包括DB.BeginTx()
:
在提交或回滚事务之前,将使用提供的上下文。如果取消上下文,sql包将回滚事务。如果提供给BeginTx的上下文被取消,Tx.Commit将返回错误。
这是context.Context
的主要用途:跨API边界进行截止日期和信号取消,并且以并发安全的方式完成(因为Context
值是不可变的,并且通道也是安全的并发使用,数据竞赛不会发生,设计;更多内容:If I am using channels properly should I need to use mutexes?)。
相关博文:
The Go Blog: Go Concurrency Patterns: Context
Pitfalls of context values and how to avoid or mitigate them in Go