go - ctx超时时,如何完全终止正在运行的go func()?

标签 go

当我想要ctx超时时,我应该怎么做才能完全终止正在执行longRunningCalculation()的方法?

package main

import (
    "context"
    "log"
    "time"
)

func longRunningCalculation(timeCost int) chan string {
    result := make(chan string)
    go func() {
        time.Sleep(time.Second * (time.Duration(timeCost)))
        log.Println("Still doing other things...") //Even if it times out, this goroutine is still doing other tasks.
        result <- "Done"
        log.Println(timeCost)
    }()
    return result
}
func jobWithTimeout() {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()
    select {
    case <-ctx.Done():
        log.Println(ctx.Err())
        return
    case result := <-longRunningCalculation(3):
        log.Println(result)
    }
}

func main() {
    jobWithTimeout()
    time.Sleep(time.Second * 5)
}


您期望看到什么?
2019/09/25 11:00:16上下文截止日期已超过

您看到了什么?
2019/09/25 11:00:16上下文截止日期已超过
2019/09/25 11:00:17还在做其他事情...

最佳答案

要在调用者的上下文超时时停止由longRunningCalculation启动的goroutine,您需要将ctx传递到longRunningCalculation中,并显式处理上下文超时,与在jobWithTimeout中所做的相同

这样操作还意味着,而不是调用time.Sleeptime.Tick将是一个更好的选择,因此这两个计时器都同时运行。像这样:

package main

import (
    "context"
    "log"
    "time"
)

func longRunningCalculation(ctx context.Context, timeCost int) chan string {
    result := make(chan string)
    go func() {
        calcDone := time.Tick(time.Second * time.Duration(timeCost))
        log.Printf("entering select (longRunningCalculation)")
        select {
        case <-ctx.Done():
            result <- "Caller timed out"
            return
        case <-calcDone:
            log.Println("Still doing other things...") //Even if it times out, this goroutine is still doing other tasks.
            result <- "Done"
        }
        log.Println(timeCost)
    }()
    return result
}

func jobWithTimeout() {
    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
    defer cancel()
    result := longRunningCalculation(ctx, 3)
    log.Printf("entering select (jobWithTimeout)")
    select {
    case <-ctx.Done():
        log.Println(ctx.Err())
        return
    case res := <-result:
        log.Println(res)
    }
}

func main() {
    jobWithTimeout()
}

关于go - ctx超时时,如何完全终止正在运行的go func()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58090804/

相关文章:

go - 为什么所有的 goroutines 都睡着了——ticker 死锁了?

Go - 接口(interface)转换[恢复] - 错误

go - 如果不符合要求的级别,是否会执行 glog 内容

dictionary - 将 map[string]string 转换为 map[someStruct]string

arrays - 为什么 go 允许从 len(slice) 进行 slice ?

go - negroni 中不同路由的不同中间件

gousb - 不是 OUT 端点

string - 将字符串转换为 uint16

session - 我应该为 mgo 中的每个操作复制 session 吗?

go - "A Tour of Go"想表达什么?