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

Mat*_*ipe 6 transactions timer go

在Golang,我对将下游传递给其他方法和函数的意图相当新contexts.我理解一个如何context工作,如何使用它,它如何保持其价值,它如何与父母context及其行为相关 - 我只是不明白为什么首先使用一个上下文.

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

我们决定采取的一个明显的解决方案是,在我们投入时间来解决根本原因之前,我们的约束是杀死超过5分钟的查询.

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

1)使用新的上下文:

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

  • 观察a中的Done频道,go routine并在那里有信号时终止该事务

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

2)使用Timer:

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

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

icz*_*cza 11

答案在于context.Contexttime.Timer传递(取消)信号的方式。

context.Context使您可以通过该Context.Done()方法访问通道,该方法将在使用它的 goroutine 终止时关闭

time.Timer使您可以访问Timer.Cstruct 字段中的通道,在给定时间段后将在该通道上发送值(该值将是当前时间,但在这里并不重要)。

在那里,重点突出显示。通道关闭可以被任意数量的 goroutine 观察到,并且可以无限次地观察到。规格:接收操作员:

关闭通道上的接收操作总是可以立即进行,在接收到任何先前发送的值后产生元素类型的零值

因此 aContext可用于向任意数量的 goroutine 和位置发出取消信号。ATimer只能用于向一个目标发出信号,即从其通道接收值的目标。如果多个客户端正在收听或尝试从其频道接收,则只有一个会幸运地接收到它。

此外,如果您正在使用 / 处理已经支持 / expects 的代码context.Context,那么使用哪一个就不是问题了。Go 1.8 还添加了更多上下文支持。对具有上下文支持的软件包进行了大量添加database/sql;包括DB.BeginTx()

提供的上下文将一直使用,直到事务提交或回滚。如果上下文被取消,sql 包会回滚事务。如果取消提供给 BeginTx 的上下文,Tx.Commit 将返回错误。

这是 : 的主要用途context.Context:跨越 API 边界传递截止日期和信号取消,并且以并发安全的方式完成(因为Context值是不可变的,并且通道对于并发使用也是安全的,按照设计不会发生数据竞争;更多相关信息:如果我正确使用通道,是否需要使用互斥锁?)。

相关博文:

Go 博客:Go 并发模式:上下文

上下文值的陷阱以及如何在 Go 中避免或减轻它们

戴夫·切尼:上下文是为了取消

  • @Gibbs 一个简单的例子:你有一个 HTTP 处理程序,它在它的 goroutine 中完成工作。它可以执行数据库日志记录,并且可以在单独的 goroutine 中同时执行此操作。如果需要中止其工作,该单独的 goroutine 可以使用/监视请求的上下文。 (2认同)