go语言通道

本文介绍了Go语言中通道的使用,包括初始化、有缓存与无缓存通道的区别,并通过实例展示了在协程中如何进行读写操作。通道初始化必须通过make函数,缓存大小由第二个参数决定,且必须大于1。文中详细分析了各种情况下的阻塞行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注意:通道首先要通过make函数来初始化,初始化之后才可以执行写入和读取操作。此外还分为【有缓存通道】和【无缓存通道】,make函数第二个参数大于1,表示有缓存;make函数的第二个参数的类型为整型,在使用make函数初始化通道时,缓存必须大于1。不可以是0。

首先看一下通道在一个协程中的例子

发送操作阻塞
package main

func main() {
	var ch chan struct{}
	//ch = make(chan struct{}, 1)
	ch <- struct{}{}
	<-ch
}

运行结果

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send (nil chan)]:
main.main()

发送(写入)操作阻塞,此外通道没有初始化,nil chan表示通道没有初始化。

接收操作阻塞
package main

func main() {
	var ch chan struct{}
	ch = make(chan struct{}, 1)
	<-ch //程序到这一行直接阻塞,即使有缓存也不行,因为通道为空,读不到数据。
	ch <- struct{}{}
}

运行结果

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()

读取(接收)操作阻塞,即使有缓存也会继续阻塞,因为通道为空,读取不到数据,后面的代码不会执行了。

编译通过
package main

func main() {
	var ch chan struct{}
	ch = make(chan struct{}, 1)
	ch <- struct{}{}
	<-ch
}

因为有缓存,所以可以往通道里写入数据,即使把最后一行注释掉,程序也可以正常运行,不会阻塞。

分别在两个协程中进行读取(接收)和写入(发送),一边读取,一边写入

读取写入均阻塞
package main

func main() {
	var ch chan struct{}
	go func() {
		ch <- struct{}{}
	}()
	<-ch
}

运行结果

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive (nil chan)]:
main.main()

goroutine 4 [chan send (nil chan)]:
main.main.func1(0x0)
created by main.main

虽然程序可以一直执行到最后一行,但是因为通道没有初始化,所以两边都阻塞。

接收操作阻塞
package main

func main() {
	var ch chan struct{}
	ch = make(chan struct{})
	<-ch
	go func() {
		ch <- struct{}{}
	}()
}

运行结果

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.main()

主函数接收操作首先阻塞,后面的代码不会执行了,即使通道有缓存也会阻塞,因为通道为空,读取不到数据。

发送和接收均阻塞
package main

func main() {
	var ch chan struct{}
	go func() {
		<-ch
	}()
	ch <- struct{}{} //程序一直可以执行到这一行,但是通道没有初始化,所以两边都阻塞。
}

运行结果

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send (nil chan)]:
main.main()

goroutine 17 [chan receive (nil chan)]:
main.main.func1(0x0)
created by main.main

虽然程序一直可以执行到最后一行,但是因为通道没有初始化,所以两边都阻塞,这个例子是主函数里边写入,子协程里边读取,与上一个两边均阻塞的正好反过来。

发送操作阻塞
package main

func main() {
	var ch chan struct{}
	ch = make(chan struct{})
	ch <- struct{}{} //函数执行到这一行直接阻塞,不管有无缓存,都会阻塞
	go func() {
		<-ch
	}()
}

运行结果

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:
main.main()

主函数发送(写入)操作先阻塞了,后面的代码不会执行了,不管通道有无缓存,程序都已经阻塞不会再继续往下执行了。

另一个协程准备好了接收数据
package main

func main() {
	var ch chan struct{}
	ch = make(chan struct{})
	go func() {
		<-ch
	}()
	ch <- struct{}{} //因为另一个协程已经准备好了接收,所以通道无缓存,程序也可以运行
}

因为另一个协程准备好了读取数据,所以即使通道无缓存也可以正常运行。

另一个协程往通道中写入了数据
package main

func main() {
	var ch chan struct{}
	ch = make(chan struct{})
	go func() {
		ch <- struct{}{}
	}()
	<-ch //程序一直可以执行到这一行,而另一个协程准备好了往通道里写入了数据,所以即使通道无缓存,也可以正常运行。
}

因为另一个协程已经准备好了往通道里写入数据,所以通道无缓存也不会阻塞。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值