2014-10-18 52 views
4

除非您在文件操作中阻止通道通信,否则似乎不可能通过通道与执行文件操作的goroutine进行双向通信。我该如何解决这个限制呢?在Go中,如何关闭长时间运行的读取?

另一种方式来短语这个问题...

如果我有相似的循环下在运行的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时使用该引用,该引用在例程内部/外部使用,但会导致外部代码阻塞,直到挂起的读取完成,并且我特别希望能够中断内联进度阅读。

回答

4

为了解决这种情况,标准库中的几个io.ReadCloser实现支持ReadClose的并发调用,其中Close会中断活动的Read。

net/http Transport创建的响应身体阅读器就是其中一种实现。在响应主体上同时调用Read和Close是安全的。

您也可以通过调用Transport CancelRequest method中断响应主体上的主动读取。

以下是如何使用接近对身体工具取消:

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 
    } 
} 

呼吁人体接近(完成)从另一个够程将取消读取。

+1

因此,调用response.Body.Close()会立即中断读取并关闭网络连接?或者我需要去掉Transport并调用CancelRequest? – DonGar 2014-10-18 16:30:10

相关问题