时间:2021.11.15
环境:Windows
目的:go程及多go程使用channel接收数据
说明:
作者:Zhong QQ交流群:121160124 欢迎加入!
在go语言开发中 使用go程可以很方便的实现并发的效果 以提升效率
有时候需要收集go程的结果 那么可以使用channel
一般我们可以这样 使用 go程 + channel + sync.WaitGroup 实现 并发、等待go程完成和收集结果
package main
import (
"fmt"
"time"
"sync"
)
func main() {
var wg sync.WaitGroup
ch := make(chan interface{})
for i := 0; i < 5; i++ {
wg.Add(1)
i := i
go func() {
defer wg.Done()
ch <- []interface{}{i} // i不会重复
}()
}
go func() {
defer close(ch)
wg.Wait()
}()
time.Sleep(time.Second)
for msg := range ch {
fmt.Println(msg) // 数据全面
}
}
上面是一种常见的实现方法 使用了一个go程来等待wg的完成和关闭channel 相对于网上很多的demo做了优化(网上很多的例子都是不负责的 随意给个demo看似拿来就能用 但往往产生的结果并并不是期望的那样)
那接下来继续深入一下 上面是基础的一个for循环来生成多个go程并发的执行 但如果是多层循环是如何优雅并全面收集结果的呢?其实这种需求在生产中很多很常见 网上大多没有提及或者代码存在bug(不是期望的结果)
使用以下方法可以优雅的做到
package main
import (
"fmt"
"time"
"sync"
)
var ch chan interface{}
var wg sync.WaitGroup
func main() {
//1. 外层循环
for j := 0; j < 5; j++ {
ch = make(chan interface{}, 2)
//2. 内层循环
for i := 0; i < 5; i++ {
wg.Add(1)
i := i
go func() {
defer wg.Done()
ch <- []interface{}{i} // i不会重复
}()
}
//3. 不能放在for循环之上 否则go func()与for循环之间若有耗时很可能提前close ch
go func() {
defer close(ch)
wg.Wait()
}()
time.Sleep(time.Second)
//4.读取一次外层循环的ch数据
for msg := range ch {
fmt.Printf("%v", msg) // 数据全面
}
fmt.Println()
}
}
上面的举例是比较常见的经典用法 下面这篇文章列举了更多使用方法:
Golang并发协程/Channel控制https://blog.youkuaiyun.com/anyedianxia/article/details/123394357
主要详述了channel特性、关闭原则以及如下场景的举例:
1个发送者 1个接收者
1个发送者 n个接收者
n个发送者 1个接收者
n个发送者 n个接收者
关注微信公众号 加入qq聊天群: 121160124