Golang中遇到无法理解的死锁问题如何解决

Golang中遇到无法理解的死锁问题如何解决

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int, 10)

	i := 100

	go func() {
		ch <- i
		i++
		time.Sleep(time.Second * 2)
	}()

	for i := range ch {
		println(i)
	}

	fmt.Println("end...")
}

致命错误:所有goroutine都处于休眠状态 - 死锁!

我无法理解为什么这段代码会失败。 我认为死锁是绝不可能发生的。


更多关于Golang中遇到无法理解的死锁问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

欢迎。请随时"标记为已解决"来关闭该工单。

更多关于Golang中遇到无法理解的死锁问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


哦!感谢您的友好回复 🙂

我完全明白了。谢谢!

感谢回复 🙂

fmt.Println 是正确的,不是 println

我想重复发送一些值(100,101,102 … N),但你的代码只发送一次就结束了。我该如何构建接收器(range 循环)和发送器(go 协程)?

欢迎来到 Golang 桥社区!🚀🎆


1. 忘记关闭通道

如果你正在使用通道循环(for i := range ch),你需要在发送端完成操作后关闭通道。在你的子例程中,你将值传入通道并休眠。因此,正确的修正应该是:

        ...
        go func() {
                ch <- i
                i++
                time.Sleep(time.Second * 2)
                close(ch)
        }
        ...

编辑:

原因:main 函数永远等待

main 函数持续等待通道关闭,以便安全地继续执行 range 循环。然而,协程没有发送关闭信号就结束了,导致 for 循环永远等待(死锁等待)。这就是你遇到死锁的原因。

2. 附注:错误代码

在你的 for 循环中,println(i) 是一个未知函数。应该是 fmt.Println(i) 吗?


交叉检查

package main

import (
	"fmt"
	"time"
)

func main() {
	ch := make(chan int, 10)
	i := 100

	go func() {
		ch <- i
		i++
		time.Sleep(time.Second * 2)
		close(ch)
	}()

	for i := range ch {
		fmt.Println(i)
	}

	fmt.Println("[ END ]")
}
// 输出:
// 100
// [ END ]

我想重复发送一些值(100,101,102…N),但你的代码只发送一次就结束了。如何构建接收器(range循环)和发送器(协程)?

这需要从清晰明确的数据传输并发规划开始。你可以使用流程图或伪代码。以下是使用伪代码的示例:

进程0(main):

  1. 创建具有10个缓冲空间的通道
  2. 将i上限设置为100
  3. 启动p1进程
  4. 开始从通道读取直到其关闭
  5. 终止整个程序

进程1(命名为p1):

  1. 从0到上限进行循环,命名为value
  2. 对每个value,将value发送到通道然后休眠2秒
  3. 完成后关闭通道
  4. 终止p1进程

关键词:

  1. 必须明确"谁在何时做什么",每个进程的每个步骤都要清晰。

你可以自己尝试实现。我已重新编写了匹配伪代码的示例,请自觉遵守要求,好吗?

示例答案:

package main

import (
	"fmt"
	"time"
)

func p1(limit int, ch chan int) {
	for value := 0; value < limit; value++ {
		ch <- value
		time.Sleep(time.Second * 2)
	}

	// done with operation, close channel.
	close(ch)
}

func main() {
	ch := make(chan int, 10)
	i := 100

	// start p1 process
	go p1(i, ch)

	// read from channel
	for i := range ch {
		fmt.Println(i)
	}

	fmt.Println("[ END ]")
}
回到顶部