为了账号安全,请及时绑定邮箱和手机立即绑定

在 Go 中,如何关闭长时间运行的读取?

在 Go 中,如何关闭长时间运行的读取?

Go
慕容森 2021-08-23 16:44:50
似乎不可能通过通道与执行文件操作的 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 的引用加锁,但会导致外部代码阻塞,直到挂起的读取完成,我特别希望能够中断正在进行的读取。
查看完整描述

1 回答

?
慕斯709654

TA贡献1840条经验 获得超5个赞

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


由 net/http Transport创建的响应正文阅读器是这些实现之一。在响应主体上同时调用 Read 和 Close 是安全的。


您还可以通过调用Transport CancelRequest 方法来中断响应正文上的活动读取。


以下是如何在 body 上使用 close 实现取消:


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) 将取消对主体的读取。


查看完整回答
反对 回复 2021-08-23
  • 1 回答
  • 0 关注
  • 233 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信