如何在context.WithDeadline或简单的计时器之间做出决定?

时间:2017-02-21 04:59:07

标签: go timer transactions

在Golang中,我对将contexts下游传递给其他方法和函数的意图相当陌生。我了解context如何运作,如何使用,如何保持其价值,如何与父context及其行为相关 - 我只是不明白为什么首先使用上下文。

在一个更具体的例子中,这是这个问题的实际原因,在我工作的公司中,我们已经确定了一些由于边缘情况而经常发生的长时间运行的查询。

我们决定采取一个明显的解决方案,考虑到我们的限制,直到我们花时间来解决根本原因,就是杀死超过5分钟的查询。

运行我们的事务的方法接受最初在API调用中启动的context。这个context一直传递给事务函数。那一刻,我找到了两个解决方案来解决这个问题:

1)使用新的上下文:

  • 发起新的context.WithTimeout(ctx, time.Duration( 5 * time.Minute) )

  • 观看Done中的go routine频道,并在有信号时终止该交易

  • 如果事务及时成功完成,只需cancel上下文并按预期提交事务。

2)使用Timer

  • 创建一个持续时间为5分钟的Timer
  • 如果时间结束,请终止交易
  • 否则,提交交易。

从逻辑上讲,它们是同一个解决方案,但是,何时以及如何决定是否使用context设置截止日期或旧的Timer

1 个答案:

答案 0 :(得分:3)

答案在于context.Contexttime.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 supportsignificant 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

Dave Cheney: Context is for cancelation