登录
首页 >  Golang >  Go问答

一旦通道中有新值就杀死 goroutine

来源:stackoverflow

时间:2024-04-06 18:51:34 293浏览 收藏

目前golang学习网上已经有很多关于Golang的文章了,自己在初次阅读这些文章中,也见识到了很多学习思路;那么本文《一旦通道中有新值就杀死 goroutine》,也希望能帮助到大家,如果阅读完后真的对你学习Golang有帮助,欢迎动动手指,评论留言并分享~

问题内容

对于通道中的每个新值,都会生成一个 goroutine。当通道中有新值时,我希望启动一个新的 goroutine,并杀死旧的 goroutine。我怀疑我的代码正在杀死新的 goroutine 并保持第一个 goroutine 的存活。我该如何解决这个问题?

func Start() {
    go func() {
        quit := make(chan bool, 1)
        for nbp := range poll() {
            quit <- true
            go create(nbp, quit)
        }
    }()
}

func create(nbp map[string]string, , quit chan bool) {
    for {
        select {
        case <-quit:
            fmt.Println("quiting this goroutine!")
            return
        default:
            for k, v := range nbp {
            ...
            }
            time.Sleep(3 * time.Second)
        }
    }
}

正确答案


一个简单的解决方法如下所示

package main

func start() {
    go func() {
        var i int
        quit := make(chan bool)
        for nbp := range poll() {
            if i > 0 {
                quit <- true
            }
            i++
            go create(nbp, quit)
        }
    }()
}

func create(nbp map[string]string, quit chan bool) {
    for {
        select {
        case <-quit:
            fmt.println("quiting this goroutine!")
            return
        default:
            for k, v := range nbp {
            //...
            }
            time.sleep(3 * time.second)
        }
    }
}

因此,查看您提供的代码,您希望每次 poll 提供新数据时启动一个新例程。这很简单:

func start() {
    for nbp := range poll() {
        go create(nbp)
    }
}

func create(nbp map[string]string) {
    // do stuff here
}

好的,但是通过这种方法,您可能会同时产生大量例程。您正在使用的 quit 通道建议您只想在前一个例程完成后生成一个新例程。同样,实现这一点很简单:

func start() {
    ch := make(chan struct{}) // struct{} is 0 bytes in size as per spec
    defer close(ch) // close channel when done
    for nbp := range poll() {
        go create(nbp, ch)
        ch <- struct{}{} // blocks until the routine has read from the channel
    }
}

func create(nbp map[string]string, ch <-chan struct{}) {
    for k, v := range nbp {
        // ... do stuff
    }
    time.sleep(3 * time.second)
    <-ch // read to unblock start
}

太好了,但现在我们只是按顺序做事,并使用一个毫无意义的渠道来做到这一点......为什么不简单地这样做:

func Start() {
    ch := make(chan map[string]string) // data in the channel
    defer close(ch) // close channel when done
    go create(ch) // start the routine reading data from the channel
    for nbp := range poll() {
        ch <- nbp // put data on channel, blocks until routine reads from the channel
        time.Sleep(3 * time.Second) // sleep here
    }
}

func create(nbp <-chan map[string]string) {
    for nbp := range ch { // read from channel
        // and process sequentially
        for k, v := range nbp {
            // ... do stuff
        }
    }
}

我将睡眠移至写入通道的循环的原因是因为在第一次迭代时,例程将立即从通道读取(它尚未执行任何操作),并解锁 poll() 循环。这将导致快速连续 2 次调用 poll()。将睡眠从例行公事中移出可确保您在第一次和第二次通话之间至少有 3 秒的时间。之后,行为几乎相同。我说得差不多了,因为您不必每次都“打扰”运行时和调度程序以释放与 create 例程相关的资源,并在之后立即调度一个新例程。

本篇关于《一旦通道中有新值就杀死 goroutine》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于Golang的相关知识,请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>