我在Go中编写了以下简短程序,试图透明地压缩阅读器中的数据(https://play.golang.org/p/SnvYT6it5r):
package main
import (
"fmt"
"io"
"bytes"
"compress/gzip"
)
func main() {
data := bytes.NewReader([]byte("hello world"))
compress(data)
}
func compress(data io.Reader) (io.Reader, error) {
pr, pw := io.Pipe()
gw := gzip.NewWriter(pw)
n, err := io.Copy(gw, data)
if err != nil {
fmt.Printf("error: %s", err.Error())
} else {
fmt.Printf("%d bytes compressed", n)
}
return pr, err
}
当我运行它时,程序挂起:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [semacquire]:
sync.runtime_notifyListWait(0x1043e6cc, 0x0)
/usr/local/go/src/runtime/sema.go:297 +0x140
sync.(*Cond).Wait(0x1043e6c4, 0x137118)
/usr/local/go/src/sync/cond.go:57 +0xc0
io.(*pipe).write(0x1043e680, 0x1045a055, 0xa, 0xa, 0x0, 0x0, 0x0, 0x101)
/usr/local/go/src/io/pipe.go:90 +0x1a0
io.(*PipeWriter).Write(0x1040c180, 0x1045a055, 0xa, 0xa, 0xe205ef63, 0x34c, 0x0, 0x0)
/usr/local/go/src/io/pipe.go:157 +0x40
compress/gzip.(*Writer).Write(0x1045a000, 0x1040a130, 0xb, 0x10, 0x2c380, 0x7654, 0x1059e0, 0x111480)
/usr/local/go/src/compress/gzip/gzip.go:168 +0x2e0
bytes.(*Reader).WriteTo(0x10440240, 0x190610, 0x1045a000, 0x0, 0xfef64000, 0x10440240, 0x1045a001, 0x190670)
/usr/local/go/src/bytes/reader.go:134 +0xe0
io.copyBuffer(0x190610, 0x1045a000, 0x1905d0, 0x10440240, 0x0, 0x0, 0x0, 0x106620, 0x1045a000, 0x0, ...)
/usr/local/go/src/io/io.go:380 +0x360
io.Copy(0x190610, 0x1045a000, 0x1905d0, 0x10440240, 0x10440240, 0x0, 0x1a47c0, 0x0)
/usr/local/go/src/io/io.go:360 +0x60
main.compress(0x1905d0, 0x10440240, 0x10440240, 0x1040c170, 0x1040a130, 0xb)
/tmp/sandbox403912545/main.go:19 +0x180
main.main()
/tmp/sandbox403912545/main.go:12 +0xe0
导致死锁的原因是什么,从阅读器压缩数据的最有效方法是什么?
答案 0 :(得分:3)
你写信给io.Pipe
,但你从来没有读过它(在并行的例程中),因此死锁。以下是文档的说法:
管道上的读取和写入是一对一匹配的,除非需要多次读取以消耗单个写入。也就是说,每个写入PipeWriter的块都会阻塞,直到满足一个或多个完全消耗写入数据的PipeReader 读取为止。数据直接从Write复制到相应的Read(或Reads);没有内部缓冲。