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个,而读的线程只有一个(主线程)。写的速度比读的快。当是无缓存时,情况是读完一个写一个。有缓存时,不必等读,直接可以写入缓存,
有疑问加站长微信联系(非本文作者)