Go语言:context使用的示例

    技术2025-04-18  10

    context主要是用于多个协程之间的统一控制,主要包括统一取消和统一超时。下面是关于context对多个协程进行统一控制的示例:

     假设有这样一个应用场景,一个公司(main)有一名经理(manager)和两名工人(worker),公司下班(main exit)有两种可能:一:工人(worker)的工作时间已经达到合同约定的最大时长;二:经理(manager)提前叫停收工。两种可能满足其中一个即可下班。

    示例:

    package main import ( "context" "fmt" "time" ) //worker工作的最大时长,超过这个时长worker自行收工无需等待manager叫停 const MAX_WORKING_DURATION = 5 * time.Second //达到实际工作时长后,manager可以提前叫停 const ACTUAL_WORKING_DURATION = 10 * time.Second func main() { ctxWithCancel, cancel := context.WithTimeout(context.Background(), MAX_WORKING_DURATION) go worker(ctxWithCancel, "[1]") go worker(ctxWithCancel, "[2]") go manager(cancel) <-ctxWithCancel.Done() //暂停1秒便于协程的打印输出 time.Sleep(1 * time.Second) fmt.Println("company closed") } func manager(cancel func()){ time.Sleep(ACTUAL_WORKING_DURATION) fmt.Println("manager called cancel()") cancel() } func worker(ctxWithCancel context.Context, name string) { for { select { case <-ctxWithCancel.Done(): fmt.Println(name, "return for ctxWithCancel.Done()") return default: fmt.Println(name, "working") } time.Sleep(1 * time.Second) } }

    输出:

    [1] working [2] working [2] working [1] working [1] working [2] working [2] working [1] working [1] working [2] working [1] return for ctxWithCancel.Done() [2] return for ctxWithCancel.Done() company closed

    可见,这次下班是因为ctxWithCancel的计时器到点引起的。

    把实际工作时长改成2秒,最大工作时长不变,再运行一次

    //worker工作的最大时长,超过这个时长worker自行收工无需等待manager叫停 const MAX_WORKING_DURATION = 5 * time.Second //达到实际工作时长后,manager可以提前叫停 const ACTUAL_WORKING_DURATION = 2 * time.Second

    输出:

    [1] working [2] working [2] working [1] working manager called cancel() [1] return for ctxWithCancel.Done() [2] return for ctxWithCancel.Done() company closed

    可见,worker只工作了2秒就被manager提前叫停了。

    至于为什么要用context而不是用计时器加通道来实现,请见另一篇文章《Go语言:为什么要使用上下文(context)而不是计时器(timer)加通道(channel)的方式来控制协程》

    Processed: 0.010, SQL: 9