GO语言中chan嵌套的使用

引言

最近在学习go语言中遇到一个爬虫项目的教学,其中有在schduler中使用双层chan的应用场景。并不太明白为甚要嵌套形成chan chan的结构,最近从网上找了点资料才明白是为了避免出现后进先出(LIFO)的情况,对协程起到了很好的管理实现先进先出(FIFO)的要求。

双chan示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
> util.go
package util

import (
"sync"
)

func DoubleChan(cc chan chan string, str string, wg *sync.WaitGroup) {
//创建一个chan
c := make(chan string)
//用于阻塞住双层chan中的一个chan
cc <- c
wg.Add(1)
go func(str string) {
//把值传入到被阻塞住的chan里
c <- str
time.Sleep(time.Microsecond * 100)
wg.Done()
}(str)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
> main.go
package main

import (
"fmt"
"strconv"
"sync"

"1234.com/test/util"
)

func main() {
wg := sync.WaitGroup{}
//创建一个双层chan
cc := make(chan chan string, 5000)
go getstr(cc)
for i := 0; i < 1000; i++ {
str := `Number:` + strconv.Itoa(i)
util.DoubleChan(cc, str, &wg)
}
wg.Wait()
}

func getstr(getstr chan chan string) {
for {
//从双层chan中取一个chan出来
c := <-getstr
//再从chan里面取值出来
r := <-c
fmt.Println(r)
}
}

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$>go run mian.go
Number:0
Number:1
Number:2
Number:3
Number:4
Number:5
Number:6
Number:7
Number:8
.
.
.
Number:999

单chan示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
util.go
package util

import (
"sync"
)

func SingleChan(cc chan string, str string, wg *sync.WaitGroup) {
wg.Add(1)
go func(str string) {
cc <- str
// time.Sleep(time.Microsecond * 100)
wg.Done()
}(str)

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
main.go
package main

import (
"fmt"
"strconv"
"sync"

"1234.co/test/util"
)

func main() {
wg := sync.WaitGroup{}
sc := make(chan string, 5000)
go getstr1(sc)
for i := 0; i < 1000; i++ {
str := `Number:` + strconv.Itoa(i)
util.SingleChan(sc, str, &wg)
}
wg.Wait()
}
func getstr1(ch chan string) {
for {
c := <-ch
fmt.Println(c)
}
}

输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
go run mian.go
Number:1
Number:0
Number:2
Number:7
Number:3
Number:4
Number:5
Number:6
Number:13
Number:12
Number:11
Number:8
Number:9
Number:10
.
.
.
Number:185
Number:188
Number:189

结论

双通道会利用通道阻塞的原理将无序的内通道,按照用户意愿的顺序压入外通道,从外通道取的值既是用户意愿的顺序。