一、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,因为它俩都不阻塞。