Golang中如何解决死锁错误

Golang中如何解决死锁错误 尝试解决打印数值时出现的死锁问题
同时如何让数值按顺序打印?
代码示例链接

7 回复

你所说的"按顺序打印"是什么意思?如果你在切片 a 上使用 range,这将会按照 a 的顺序进行。

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


按顺序打印,就像最初创建时那样,即 1,3,10,8… 当我运行程序时,输出通常是随机顺序的

谢谢。有没有办法让这个版本按顺序打印而不使用通道?或者这就是通道的唯一用途? https://play.golang.org/p/USuv8dsdlfH

我上面包含的版本按顺序将 a 的元素写入 cPrint 以相同顺序从 c 读取。

你最后链接的代码片段在 a 上使用 range,并为 a 中的每个元素启动一个新的 goroutine。这 6 个 goroutine 的执行顺序是不确定的。这就是为什么结果看起来是随机的。但这与通道无关,而是 go func 的工作方式。

一些观察:

  • wg 作为参数传递给 Print
  • 不要调用 wg.Add(6),只需调用 wg.Add(1)
  • 让写入 c 的 goroutine 调用 close(c)
  • Print 开头调用 defer wg.Done()

这样是可行的:

package main

import (
	"fmt"
	"sync"
)

func main() {
	c := make(chan int)

	a := []int{1, 3, 10, 8, 15, 23}

	go func(i []int) {
		for _, v := range i {
			c <- v
		}
		close(c)
	}(a)

	var wg sync.WaitGroup

	wg.Add(1)
	go Print(c, &wg)
	wg.Wait()
}

func Print(c chan int, wg *sync.WaitGroup) {
	defer wg.Done()
	for v := range c {
		fmt.Println(v)
	}
}

https://play.golang.org/p/RYW2WbzJbtJ

在Go语言中,死锁通常发生在goroutine之间因等待彼此释放资源而陷入无限阻塞的情况。根据你提供的代码示例,问题主要源于通道(channel)的使用不当:主goroutine等待从通道接收数据,而其他goroutine在发送数据后没有正确关闭或处理通道,导致主goroutine永远阻塞。

以下是解决死锁并让数值按顺序打印的修改方案。我们使用带缓冲的通道和同步机制(如WaitGroup)来协调goroutine的执行顺序。

修改后的代码示例:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	ch := make(chan int, 3) // 使用带缓冲的通道,容量为3

	// 启动3个goroutine,每个发送一个数值到通道
	for i := 1; i <= 3; i++ {
		wg.Add(1)
		go func(num int) {
			defer wg.Done()
			ch <- num
		}(i)
	}

	// 启动一个独立的goroutine来等待所有发送完成并关闭通道
	go func() {
		wg.Wait()
		close(ch)
	}()

	// 从通道接收数据并按顺序打印
	for num := range ch {
		fmt.Println(num)
	}
}

代码解释:

  1. 带缓冲的通道ch := make(chan int, 3) 创建了一个缓冲容量为3的通道,允许发送goroutine在没有立即接收的情况下完成操作,避免阻塞。
  2. WaitGroup同步wg.Add(1)wg.Done() 用于跟踪所有goroutine的完成状态。wg.Wait() 会阻塞直到所有goroutine执行完毕。
  3. 关闭通道:在独立goroutine中调用 close(ch) 确保所有数据发送完成后关闭通道,这样主goroutine中的 range ch 循环会在接收完所有数据后正常退出,避免死锁。
  4. 顺序打印:由于通道是先进先出(FIFO)的,数值会按照发送顺序(1、2、3)打印。如果goroutine启动顺序固定,输出将保持一致。

运行结果:

1
2
3

如果要求严格按goroutine启动顺序打印,上述方法足够;如果涉及复杂顺序控制,可考虑使用同步原语如Mutex或条件变量。此方案消除了死锁并确保了顺序性。

回到顶部