Golang中如何同时读写处理两个Channel

Golang中如何同时读写处理两个Channel 你好,

我正在尝试做一些事情来理解并解决类似“所有goroutine都处于休眠状态 - 死锁!”的问题。我使用了goroutine来进行读取和写入。那么为什么我还会遇到错误呢?

package main

func main() {
processData()
}

func processData() {
ch :=make(chan int , 10)
result :=make(chan int , 10)
for i:=0;i<10; i++{
go executeTask(ch, result)
}
for i:=0; i<100; i++{
ch <- i

}
for a:=0;a <10 ; a++{
	<- result
}
println("test main")
}

func executeTask(ints chan int , result chan<- int) {
for r:= range ints{
result <- 1
println(r)

}
println("execute tasks")
}

更多关于Golang中如何同时读写处理两个Channel的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

非常感谢Jakob的解释

更多关于Golang中如何同时读写处理两个Channel的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


因为你试图在读取任何响应之前发送100个项目。这100个项目需要存储在某个地方。

10个执行器goroutine读取10个项目,处理它们,并将结果写入结果缓冲区。结果缓冲区现在已经满了,因为你还没有开始读取它。

然后另外十个项目被处理,所有的执行器例程在发送结果时全部阻塞,因为结果通道已满。到目前为止,这是20个项目。

ch 通道随后缓冲了其中的10个。此时你已经发送了30个项目。

此时,没有任何进程可以继续——执行器无法发送结果,因为没有人读取结果;也无法发送新项目,因为执行器没有读取任何项目,所以系统陷入了死锁。

这是一个典型的死锁问题,原因是你的 executeTask goroutine 在 for r := range ints 循环中等待 ch 通道的数据,但 ch 通道从未被关闭,导致 goroutine 无法退出。同时,主 goroutine 在等待从 result 通道读取数据,但 executeTask 中的 result <- 1 可能因为 result 通道已满而阻塞。

以下是修改后的代码,通过关闭 ch 通道来通知 goroutine 停止接收,并确保所有 goroutine 都能完成:

package main

func main() {
    processData()
}

func processData() {
    ch := make(chan int, 10)
    result := make(chan int, 10)
    
    // 启动10个goroutine
    for i := 0; i < 10; i++ {
        go executeTask(ch, result)
    }
    
    // 发送100个数据到ch通道
    for i := 0; i < 100; i++ {
        ch <- i
    }
    
    // 关闭ch通道,通知goroutine停止接收
    close(ch)
    
    // 等待所有goroutine完成
    for a := 0; a < 100; a++ {
        <-result
    }
    
    println("test main")
}

func executeTask(ints chan int, result chan<- int) {
    for r := range ints {
        result <- 1
        println(r)
    }
    println("execute tasks")
}

关键修改:

  1. 在发送完所有数据后调用 close(ch),这样 for r := range ints 循环会在通道关闭且数据读取完毕后自动退出
  2. result 的读取次数从10改为100,因为每个处理的任务都会发送一个结果

如果你想要更精确的控制,可以使用 sync.WaitGroup

package main

import "sync"

func main() {
    processData()
}

func processData() {
    ch := make(chan int, 10)
    result := make(chan int, 10)
    var wg sync.WaitGroup
    
    // 启动10个goroutine
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            executeTask(ch, result)
        }()
    }
    
    // 发送100个数据到ch通道
    for i := 0; i < 100; i++ {
        ch <- i
    }
    
    // 关闭ch通道
    close(ch)
    
    // 等待所有goroutine完成
    wg.Wait()
    
    // 关闭result通道
    close(result)
    
    // 读取结果
    for range result {
        // 处理结果
    }
    
    println("test main")
}

func executeTask(ints chan int, result chan<- int) {
    for r := range ints {
        result <- 1
        println(r)
    }
    println("execute tasks")
}

这个版本使用 sync.WaitGroup 来等待所有 worker goroutine 完成,然后安全地关闭 result 通道。

回到顶部