channel
channel
chreadandwrite :=make(chan int)
chonlyread := make(<-chan int) //创建只读channel
chonlywrite := make(chan<- int) //创建只写channel
channel
chreadandwrite :=make(chan int, 1)
chonlyread := make(<-chan int) //创建只读channel
chonlywrite := make(chan<- int) //创建只写channel
两者区别
下面我们来看一个例子:
ch := make(chan int)
ch <- 1
go func() {
<-ch
fmt.Println("1")
}()
fmt.Println("2")
这段代码执行时会出现一个错误:fatal error: all goroutines are asleep - deadlock!
这个错误的意思是说线程陷入了死锁,程序无法继续往下执行。那么造成这种错误的原因是什么呢?
channelchannelchannelchannelchannelchannelchannelchannel
对于上面的例子有两种解决方案:
1、给channel增加缓冲区,然后在程序的最后让主线程休眠一秒,代码如下:
ch :=make(chan int,1)
ch <- 1
go func() {
v := <-ch
fmt.Println(v)
}()
time.Sleep(1 * time.Second)
fmt.Println("2")
这样的话程序就会依次打印出1、2
2、把ch<-1这一行代码放到子线程代码的后面,代码如下:
ch :=make(chan int)
go func() {
v := <-ch
fmt.Println(v)
}()
ch <- 1
fmt.Println("2")
/*
1
2
*/
这里就不用让主线程休眠了,因为channel在主线程中被赋值后,主线程就会阻塞,直到channel的值在子线程中被取出。
最后我们看一个生产者和消费者的例子:
import (
"fmt"
"time"
)
func produce(p chan<- int) {
for i := 0; i < 10; i++ {
p <- i
fmt.Println("send:", i)
}
}
func consumer(c <-chan int) {
for i := 0; i < 10; i++ {
v := <-c
fmt.Println("receive:", v)
}
}
func main() {
ch := make(chan int)
go produce(ch)
go consumer(ch)
time.Sleep(1 * time.Second)
}
在这段代码中,因为channel是没有缓冲的,所以当生产者给channel赋值后,生产者这个线程会阻塞,直到消费者线程将channel中的数据取出。消费者第一次将数据取出后,进行下一次循环时,消费者的线程也会阻塞,因为生产者还没有将数据存入,这时程序会去执行生产者的线程。程序就这样在消费者和生产者两个线程间不断切换,直到循环结束。
下面我们再看一个带缓冲的例子:
func produce(p chan<- int) {
for i := 0; i < 10; i++ {
p <- i
fmt.Println("send:", i)
}
}
func consumer(c <-chan int) {
for i := 0; i < 10; i++ {
v := <-c
fmt.Println("receive:", v)
}
}
func main() {
ch := make(chan int, 10)
go produce(ch)
go consumer(ch)
time.Sleep(1 * time.Second)
}