不会飞的章鱼

熟能生巧,勤能补拙;念念不忘,必有回响。

Golang并发中的FanIn范式学习

在学习并发时,对FaninFanout这两个范式印象深刻,特此记录一下学习心得。

介绍

扇出(Fan-out)是一个术语,用于描述启动多个goroutines以处理来自管道的输入的过程,并且扇入(fan-in)是描述将多个结果组合到一个通道中的过程的术语。

画个图

fanin

fanout

这样做有什么好处呢,下面来看看源码。

源码学习

concurrent_map.go文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Iter returns an iterator which could be used in a for range loop.
// Deprecated: using IterBuffered() will get a better performence
func (m ConcurrentMap) Iter() <-chan Tuple {
chans := snapshot(m)
ch := make(chan Tuple)
go fanIn(chans, ch)
return ch
}

func fanIn(chans []chan Tuple, out chan Tuple) {
wg := sync.WaitGroup{}
wg.Add(len(chans)) //总共要进入的管道数目
for _, ch := range chans {
go func(ch chan Tuple) {
for t := range ch { //取出每一个管道内的数据
out <- t //将数据发送给管道接收者out
}
wg.Done() //每取完一次管道内的数据,管道数目减1
}(ch)
}
wg.Wait()
close(out) //管道内的数据已经取完,关闭管道接收者out
}

画图演示下过程
chan

解释

  • sync.WaitGroup
    sync.WaitGroup只有3个方法,Add(),Done(),Wait()。其中Done()是Add(-1)的别名。简单的来说,使用Add()添加计数,Done()减掉一个计数,计数不为0, 阻塞Wait()的运行。
    因此当计数为0时,也就是要进入的管道数都没有的时候,关闭管道。

FanIn范式的用途

在此引用我看到的一段话

管道的一个有趣属性是它的各个阶段相互独立,方便组合。你可以多次重复使用管道的各个阶段。因此,在多个goroutine上重用管道的单个阶段实现并行化,将有助于提高管道的性能。
事实上,这种模式被称为扇入扇出。
那么在什么情况下适用于这种模式呢?如果出现以下两种情况,你就可以考虑这么干了:
不依赖模块之前的计算结果。
运行需要很长时间。

参考文章

------ 本文结束------
如果本篇文章对你有帮助,可以给作者加个鸡腿~(*^__^*),感谢鼓励与支持!