教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 Go中使用channel控制goroutine退出

Go中使用channel控制goroutine退出

发布时间:2022-03-23   编辑:jiaochengji.com
教程集为您提供Go中使用channel控制goroutine退出等资源,欢迎您收藏本站,我们将为您提供最新的Go中使用channel控制goroutine退出资源

1.      最近看到一个小例子,简单分析了一下函数是如何退出的,copy下代码跑了一下和自己起初想的不太一样,所以再次记录一下以免忘记。如有误请指正,代码如下:

package main

 

import (

    "fmt"

    "runtime"

    "time"

)

func main() {

    generator := func(done <-chan interface{}, integers ...int) <-chan int {

        intStream := make(chan int)

        go func() {

            defer close(intStream)

            for _, i := range integers {

                select {

                case <-done:

                    return

                case intStream <- i:

                }

            }

        }()

 

        return intStream

    }

 

    multiply := func(done <-chan interface{}, intStream <-chan int, multiplier int) <-chan int {

        multipliedStream := make(chan int)

        go func() {

            defer close(multipliedStream)

            for i := range intStream {

                select {

                case <-done:

                    return

                case multipliedStream <- i * multiplier:

                }

            }

        }()

 

        return multipliedStream

    }

 

    add := func(done <-chan interface{}, intStream <-chan int, additive int) <-chan int {

        addedStream := make(chan int)

        go func() {

            defer close(addedStream)

            for i := range intStream {

                select {

                case <-done:

                    return

                case addedStream <- i additive:

                }

            }

        }()

 

        return addedStream

    }

 

    done := make(chan interface{})

    defer close(done)

 

    intStream := generator(done, 1, 2, 3, 4)

    pipeline := multiply(done, add(done, multiply(done, intStream, 2), 1), 2)

 

    for v := range pipeline {

        fmt.Println(v)

    }

}

2.第一感觉是使用main函数的done结束的各个goroutine的,加一点打印看一下,在每个函数的select里加入一行打印信息。

 

               ......

               ...... 

                case <-done:

                    fmt.Println("generator done...")

               ......

 

看一下输出结果:

并没有打印新添加的信息,难道是goroutine没有退出? 加一段代码查看当前goroutine的变化。

......

   

    intStream := generator(done, 1, 2, 3, 4)

    pipeline := multiply(done, add(done, multiply(done, intStream, 2), 1), 2)

 

    count := runtime.NumGoroutine()

    fmt.Printf("计算前运行的goroutine数量:%d\n", count)

 

    go func() {

        time.Sleep(2 * time.Second)

        close(done)

    }()

 

    for v := range pipeline {

        fmt.Println(v)

    }

 

    count = runtime.NumGoroutine()

    fmt.Printf("计算后运行的goroutine数量:%d\n", count)

......

......

看一下输出:

“计算后运行的goroutine数量:1” 说明开启的4个goroutine已经退出了,那么是怎么退出的那?

 再次仔细看看代码发现generator的第二个参数是一个可变参数,内部当做切片使用,range 遍历传入的切片数据,当遍历完所有数据后

退出for循环也就退出了generator中的觅名函数,此时调用的defer close(intStream)这个chan ,而multiply函数依赖这个chan

当generator中的chan关闭后multiply中的 range 也结束了for循环 函数退出,退出时关闭了 multipliedStream这个chan,

 add函数依赖multipliedStream这个chan 也就随之关闭,在代码中打印的东西印证一下。

每个函数的for后边添加一行打印。

......

......

        go func() {

            defer close(intStream)

            //defer fmt.Println("generator def done....")

            for _, i := range integers {

                //fmt.Printf("rge %d \n", i)

                select {

                case <-done:

                    fmt.Println("generator done...")

                    return

                case intStream <- i:

                }

            }

            fmt.Println("generator 结束for循环")

        }()

......

 

看一下输出:

那done这个chan可以提前结束计算吗?加点东西看看。

在开启的goroutine中加入一秒的延时。

在main函数中加如代码

count := runtime.NumGoroutine()

    fmt.Printf("计算前运行的goroutine数量:%d\n", count)

 

    go func() {

        time.Sleep(2 * time.Second)

        close(done)

    }()

 

    for v := range pipeline {

        fmt.Println(v)

    }

 

    count = runtime.NumGoroutine()

    fmt.Printf("计算后运行的goroutine数量:%d\n", count)

......

......


到此这篇关于“Go中使用channel控制goroutine退出”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Golang并发编程中控制主goroutine退出实现的例子
golang goroutine 通知_深入golang之---goroutine并发控制与通信
go语言并发编程
22Go常见的并发模式和并发模型
Golang 中的 Goroutine 调度原理与 Chanel 通信
Go中使用channel控制goroutine退出
go channel 缓冲区最大限制_Golang 入门 : channel(通道)
Go并发模式:管道和取消
Golang并发:并发协程的优雅退出
goroutine泄露:原理、场景、检测和防范

[关闭]
~ ~