【问题标题】:Stop execution of the simple function using context使用上下文停止执行简单函数
【发布时间】:2020-07-20 11:38:28
【问题描述】:

据我了解,上下文库的主要目的是停止执行所有子级的 RPC 和 HTTP 请求。或者用简单的语言,我们可以说在上下文库的帮助下,我们可以将触发器传递给函数调用

这是我想使用上下文解决的抽象形式的问题。

package main

import (
    "context"
    "fmt"
    "time"
)

func PrintAndStop(ctx context.Context, numberOfTimePrint int, msg string) {
    communicationChannel := make(chan bool)
    go func() {
        for i := 0; i < numberOfTimePrint; i++ {
            fmt.Println(msg)
            time.Sleep(time.Second)
        }
        communicationChannel <- true
    }()
    select {
    case <-communicationChannel:
        fmt.Println("process has been completed")
    case <-ctx.Done():
        fmt.Println("closing call from the main function")
    }
}

func main() {
    ctx := context.Background()
    ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
    defer cancel()
    PrintAndStop(ctx, 5*time.Second, "testing")

    time.Sleep(5 * time.Second)
}

以下代码的输出是:

testing
testing
testing
closing call from the main function
testing
testing

此处提供以下代码 sn-p 的链接:https://play.golang.org/p/4Ntwn3wYOiT PrintAndStop 是一种以 1 秒的间隔打印一些消息给定次数的方法。 在上下文库的帮助下,我想控制主函数以随时停止执行PrintAndStop。 main末尾的time.Sleep(5 * time.Second)只是表示main函数在函数调用后没有结束。

我知道以下重构,但实际问题不能这样重构。

func PrintAndStop(ctx context.Context, numberOfTimePrint int, msg string) {
    completed := true
    for i := 0; i < numberOfTimePrint; i++ {
        select {
        case <-time.After(1 * time.Second):
            fmt.Println(msg)
        case <-ctx.Done():
            fmt.Println("closing call from the main function")
            completed = false
            break
        }
    }
    if completed {
        fmt.Println("function execution is completed")
    }
}

注意:我很乐意使用 context 库的一些扩展或 Go 中一些全新的库来解决上述问题。

【问题讨论】:

    标签: go concurrency


    【解决方案1】:

    我想控制主函数以随时停止执行PrintAndStop

    然后你需要检查上下文的取消在那个循环中

        go func() {
            for i := 0; i < int(timeout/time.Second); i++ {
                select {
                case <-ctx.Done():
                    return
                }
                fmt.Println(msg)
                time.Sleep(time.Second)
            }
            communicationChannel <- true
        }()
    

    【讨论】:

    • 除了在每个执行步骤中检查ctx.Done() 频道之外,没有其他选项了吗?
    • 这就是使用上下文的方式,所以不,不是真的。你为什么想要别的东西?您认为这种方法有问题吗?
    • 实际上代替 time.Sleep(),实际函数调用具有高 CPU 密集型计算。我只想在触发器来自主函数时立即停止计算。 (就像杀死一些进程)
    • 你不能“杀死” goroutines。您必须定期检查上下文是否已被取消。如果您的代码在一个紧密的循环中运行,您必须在检查过于频繁(未取消时效率低下)与检查不够频繁以及在取消时让您的代码运行时间超过必要之间找到适当的平衡。
    • 谢谢你,Flimzy,我想我必须以平衡的方式反复检查上下文变量的取消。
    猜你喜欢
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-06
    • 2017-09-01
    • 2021-06-11
    • 2017-09-05
    • 1970-01-01
    相关资源
    最近更新 更多