php小编百草在这里给大家解答一个常见的问题:“使用通道时,goroutine 的执行顺序是什么?”在Go语言中,goroutine是轻量级的线程,可以并发执行。当使用通道来进行协程间的通信时,通道的接收和发送操作是阻塞的,即它们会等待其他协程的操作完成。因此,当有多个goroutine同时操作一个通道时,它们的执行顺序是不确定的,取决于各个协程的调度情况。这就意味着,无法确定哪个goroutine会先执行,哪个会后执行,这由Go语言的调度器决定。
问题内容
使用通道时 goroutine 的执行顺序是什么?我认为写入或读取通道会停止当前的 goroutine。但我的测试代码不遵循此规则:
func main() {
ch := make(chan int)
go sum(ch, 3)
fmt.Println("Write number: 10")
ch <- 10
fmt.Println("Write number: 20")
ch <- 20
fmt.Println("Write number: 30")
ch <- 30
fmt.Println("Finish main")
}
func sum(ch chan int, len int) {
fmt.Println("Func 'sum' start")
sum := 0
for i := 0; i < len; i++ {
fmt.Println("For start")
num := <-ch
fmt.Printf("Read from ch: %d\n", num)
sum += num
fmt.Println("For finish")
}
fmt.Printf("Sum: %d\n", sum)
}
我认为这个程序如何运作:
1.创建频道
2.创建一个goroutine(不启动,只初始化)
3.打印:写下数字:10
4.录制至10频道。锁定主要功能。
5.最主要的是被挡住了。启动 sum goroutine。
6.打印求和函数:Func 'sum' start
7.求和函数循环运行并打印:“To begin”
8.从“ch”读取数字 10 并打印:“Read from ch: 10”
9.下一步。打印:“完成”并继续下一次迭代。
10。打印:“开始于”并尝试写“with”。但通道是空的。停额,进入主线
...一次又一次。
然后我想看看:
Write number: 10
Func 'sum' start
For start
Read from ch: 10
For finish
For start
Write number: 20
Read from ch: 20
For finish
For start
Write number: 30
Read from ch: 30
For finish
Sum: 60
Finish main
但是,我看到:
Write number: 10
Func 'sum' start
For start
Read from ch: 10
For finish
For start
Write number: 20
Write number: 30
Read from ch: 20
For finish
For start
Read from ch: 30
For finish
Sum: 60
Finish main
这怎么可能?主函数向通道写入两次而不读取。
另外,如果您更改 for 中的调用次数:
go sum(ch, 2)
我不会收到错误。但没有人阅读最后一条消息
示例:在此消息之前。
解决方法
Goroutines 并发运行。在具有多个内核的系统上,它们可以并行运行。详细信息取决于 Go 运行时中的调度程序实现。出于所有意图和目的,除了通道通信等同步操作之外,事情都以随机顺序发生。
事实并非如此,也不是正在发生的事情(只要通道没有缓冲)。 Println 调用发生在发送操作之前,主 Goroutine 在打印后阻塞,直到 sum Goroutine 准备好接收。
是否看到“Read from ch: 30”打印出来也是随机的。相应的接收操作必须发生,因为 main 会被阻塞,直到它发生为止。然而,main 可能会在接收发生后在 Println 之前返回,并且当 main 返回时程序会立即终止,无论是否存在任何其他 goroutine。如果通道被缓冲,发生这种情况的可能性就会增加。
事实并非如此。如果只有两个接收总是导致死锁: https://go.dev/play/p/ qFVh529mkqR
以上就是使用通道时,goroutine 的执行顺序是什么?的详细内容,更多请关注编程网其它相关文章!