Go语言自学笔记
2016-10-06 11:03
393 查看
package main import ( "fmt" ) func main() { ch := make(chan int) /* 下面2行不能互换,主程序顺序执行,若先遇到 ch<-2,则在此阻塞了。程序不会向下执行 */ go f1(ch) //开启一个协程 ch <- 2 //向channel中传送数据 } func f1(ch chan int) { fmt.Println(<-ch) //输出数据 }
如果容量大于 0,通道就是异步的了:缓冲满载(发送)或变空(接收)之前通信不会阻塞,元素会按照发送的顺序被接收。如果容量是0或者未设置,通信仅在收发双方准备好的情况下才可以成功。
要在首要位置使用无缓冲通道来设计算法,只在不确定的情况下使用缓冲。
package main import ( "fmt" ) func main() { const N int = 10 data := []int{34, 23, 45, 23, 5, 2, 1, 456, 76, 46} //10个元素 ch := make(chan int) for index, v := range data { go func(index, v int) { ch <- v fmt.Printf("index is %d,value is %d \n", index, v) }(index, v) } for i := 0; i < N; i++ { fmt.Println(<-ch) } }
输出结果为
index is 0,value is 34
34
23
45
23
5
2
1
456
76
46
解释:
程序线性执行到第一个for循环时,for循环内的goroutine开始并发执行(即重开协程执行),10次循环结束后,开启了10个并发的协程(比线程更轻量的概念),而主程序相当于跑了10次空循环。
一方面,主线程执行下一个for循环,一方面那10个协程并发执行。
主线程当遇到第一个
fmt.Println(<-ch)时,查看channel中是否有值,若有值则读取并输出,无值则等待阻塞。
goroutine的协程执行内嵌函数,
ch <- v向channel中传值,若无线程接受则会阻塞。由于主线程的第二个for有接收值,当主线程接收完值后程序退出。由结果可见协程中的输出语句只打印了一条(0-n,随机),因为主程序接收完N个channel值就会退出,而打印语句在协程中处于传值后。
然后我们看下一个例子,只是在channel创建时指定了大小,channel就成了有缓存的channel。
package main import ( "fmt" ) func main() { const N int = 10 data := []int{34, 23, 45, 23, 5, 2, 1, 456, 76, 46} ch := make(chan int, N) for index, v := range data { go func(index, v int) { ch <- v fmt.Printf("index is %d,value is %d \n", index, v) }(index, v) } for i := 0; i < N; i++ { fmt.Println(<-ch) } }
输出结果:
index is 0,value is 34
index is 1,value is 23
index is 2,value is 45
index is 3,value is 23
index is 4,value is 5
index is 5,value is 2
index is 6,value is 1
index is 7,value is 456
index is 8,value is 76
index is 9,value is 46
34
23
45
23
5
2
1
456
76
46
仅仅将channel变为有缓存结果就变了,因为写的线程有10个,而读的线程只有一个(主线程)。写的速度比读的快。当是无缓存时,情况是读完一个写一个。有缓存时,不必等读,直接可以写入缓存,
相关文章推荐