使用io.Pipe时Goroutine中io.Copy死锁问题及解决问询
问题原因
使用io.Pipe时,PipeReader的Read操作会一直阻塞,直到对应的PipeWriter被关闭或有新数据写入。原代码中,io.Copy(pipeWriter, read)完成后未关闭pipeWriter,导致goroutine内的io.Copy(os.Stdout, pipeReader)持续等待更多数据;而main goroutine卡在wg.Wait()无法推进,最终所有goroutine进入休眠状态,触发死锁。
解决方案
在完成PipeWriter的数据写入后,必须关闭PipeWriter,以此通知PipeReader数据传输结束,让io.Copy正常返回。推荐用defer确保无论写入操作成功与否,PipeWriter都会被关闭。
修改后的代码:
func main() { read := strings.NewReader("abcdefghij") pipeReader, pipeWriter := io.Pipe() var wg sync.WaitGroup wg.Add(1) go func() { defer wg.Done() println("Start copy") _, err := io.Copy(os.Stdout, pipeReader) if err != nil { println(err.Error()) } println("End copy") }() defer pipeWriter.Close() _, err := io.Copy(pipeWriter, read) if err != nil { println(err.Error()) } wg.Wait() }
关键修改点
defer pipeWriter.Close():保证PipeWriter最终被关闭,无论io.Copy是否出错,都能终止PipeReader的阻塞等待。- 将
wg.Done()放入defer:确保goroutine即使在io.Copy出错时,也能正确标记任务完成,避免wg.Wait()永久阻塞。
扩展场景说明
如果实际代码中使用io.MultiWriter连接多个PipeWriter,需要为每个PipeWriter单独执行关闭操作,确保对应的PipeReader都能收到结束信号,避免类似死锁问题。
内容的提问来源于stack exchange,提问作者EtTuBrute
相关产品推荐
相关产品推荐

