2014-10-18 35 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

相關問題