一、channel的理解可参考:[系列] Go - chan 通道 - 新亮笔记 - 博客园 (cnblogs.com)
主要点:
1、管道类似队列:队满时,入队会导致阻塞,队空时出队也会阻塞;
不带缓冲的通道,进和出都会立刻阻塞。不带缓冲的管道类似ch:=make(chan data_type,N),其中不带缓冲区是指大小参数N=0,或省略,则为非缓冲管道,即管道容量为N=0。
2、go 关键字后面加一个函数,就可以创建一个线程(goroutine),函数可以为已经写好的函数,也可以是匿名函数。
二、管道和select配合:
golang的select类似c语言、java中的switch语句,但有明显的区别:
switch语句会【逐个】执行各个case分支,然后执行default分支,除非某个case包含break语句则退出switch;
而select会【随机】地执行下面的各个非阻塞的case 语句,且每个case 语句必须是一个读或写channel的操作;当某个case 阻塞时会走到下一个case,若该case不阻塞则执行该case后退出select,若所有的case都阻塞才会执行default 分支。
package main
import "fmt"
func main() {
// test_select()
for i := 1; i <= 10; i++ {
fmt.Println("Iter No.", i)
//test_select()
test_select2()
}
}
func test_select() {
var c1, c2, c3 chan int
var i1, i2 int = 10, 20
c3 = make(chan int, 6)
c3 <- 50
select {
case i1 = <-c1:
fmt.Println("received ", i1, " from c1\n")
case c2 <- i2:
fmt.Println("sent ", i2, " to c2\n")
break
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
fmt.Println("received", i3, "from c3\n")
} else {
fmt.Println("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}
}
func test_select2() {
var c1, c2, c3 chan int
var i1, i2 int = 10, 20
c2 = make(chan int, 5)
c3 = make(chan int, 3)
c3 <- 50
select {
case i1 = <-c1:
fmt.Println("received ", i1, " from c1")
case c2 <- i2:
fmt.Println("sent ", i2, " to c2")
// break
case c3 <- 5: // same as: i3, ok := <-c3
// if ok {
// fmt.Println("received", i3, "from c3\n")
// } else {
// fmt.Println("c3 is closed\n")
// }
fmt.Println("sent ", 5, " to c3")
default:
fmt.Printf("no communication\n")
}
}
上述代码执行10次test_select()函数都是走到第3个case,若执行10次 test_select2(),则输出的结果会随机顺序执行第2、第3个case,因为它俩都不阻塞。