你所说的"按顺序打印"是什么意思?如果你在切片 a 上使用 range,这将会按照 a 的顺序进行。
更多关于Golang中如何解决死锁错误的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
按顺序打印,就像最初创建时那样,即 1,3,10,8… 当我运行程序时,输出通常是随机顺序的
谢谢。有没有办法让这个版本按顺序打印而不使用通道?或者这就是通道的唯一用途? https://play.golang.org/p/USuv8dsdlfH
我上面包含的版本按顺序将 a 的元素写入 c。Print 以相同顺序从 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)
}
}
在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)
}
}
代码解释:
- 带缓冲的通道:
ch := make(chan int, 3)创建了一个缓冲容量为3的通道,允许发送goroutine在没有立即接收的情况下完成操作,避免阻塞。 - WaitGroup同步:
wg.Add(1)和wg.Done()用于跟踪所有goroutine的完成状态。wg.Wait()会阻塞直到所有goroutine执行完毕。 - 关闭通道:在独立goroutine中调用
close(ch)确保所有数据发送完成后关闭通道,这样主goroutine中的range ch循环会在接收完所有数据后正常退出,避免死锁。 - 顺序打印:由于通道是先进先出(FIFO)的,数值会按照发送顺序(1、2、3)打印。如果goroutine启动顺序固定,输出将保持一致。
运行结果:
1
2
3
如果要求严格按goroutine启动顺序打印,上述方法足够;如果涉及复杂顺序控制,可考虑使用同步原语如Mutex或条件变量。此方案消除了死锁并确保了顺序性。


