除非您阻止文件操作上的通道通信,否则通过具有执行文件操作的goroutine的通道进行双向通信似乎不可能。我如何解决这个限制?
另一种表达这个问题的方法......
如果我在goroutine中有一个类似于以下循环的循环,我怎么能告诉它关闭连接并在下一次读取时不停止退出?
func readLines(response *http.Response, outgoing chan string) error {
defer response.Body.Close()
reader := bufio.NewReader(response.Body)
for {
line, err := reader.ReadString('\n')
if err != nil {
return err
}
outgoing <- line
}
}
它不可能从一个告诉它什么时候关闭的频道读取,因为它在网络读取时阻塞(在我的情况下,可能需要几个小时)。
从goroutine外部简单地调用Close()似乎不安全,因为Read / Close方法似乎不是完全线程安全的。
我可以简单地锁定对例程内部/外部使用的response.Body的引用,但是会导致外部代码阻塞,直到挂起的读取完成,我特别希望能够中断正在进行的操作读取。
答案 0 :(得分:5)
为了解决这种情况,标准库中的几个io.ReadCloser实现支持对Read和Close的并发调用,其中Close会中断活动的Read。
net / http Transport创建的响应正文阅读器就是其中一个实现。同时在响应主体上调用Read和Close是安全的。
您还可以通过调用Transport CancelRequest method来中断响应正文的活动读取。
以下是使用close on body取消工具的方法:
func readLines(response *http.Response, outgoing chan string, done chan struct{}) error {
cancel := make(chan struct{})
go func() {
select {
case <-done:
response.Body.Close()
case <-cancel:
return
}()
defer response.Body.Close()
defer close(cancel) // ensure that goroutine exits
reader := bufio.NewReader(response.Body)
for {
line, err := reader.ReadString('\n')
if err != nil {
return err
}
outgoing <- line
}
}
从另一个goroutine调用close(done)将取消对身体的读取。