如何在 *os.file/io.read中设置超时



我知道有一个称为 SetReadDeadline的函数,可以在套接字(conn.net)读取中设置超时,而io.read却没有。有一种方法可以启动另一个例程作为计时器来解决此问题,但是它带来了读者例程(io.read)仍然阻止的另一个问题:

func (self *TimeoutReader) Read(buf []byte) (n int, err error) { 
    ch := make(chan bool) 
    n = 0 
    err = nil 
    go func() { // this goroutime still exist even when timeout
            n, err = self.reader.Read(buf) 
            ch <- true 
    }() 
    select { 
    case <-ch: 
            return 
    case <-time.After(self.timeout): 
            return 0, errors.New("Timeout") 
    } 
    return 
} 

这个问题在这篇文章中是相似的,但是答案尚不清楚。你们有什么好主意解决这个问题吗?

而不是直接在read上设置超时,您可以在超时后close CC_3。如https://golang.org/pkg/os/#file.close

关闭关闭文件,使其无法使用I/O。在支持setDeadline的文件上,任何待处理的I/O操作都将被取消,并立即返回错误。

这应该导致您的read立即失败。

您的错误在这里是不同的:

当您从读者那里阅读时,您只读一次,这是错误的:

go func() { 
        n, err = self.reader.Read(buf) // this Read needs to be in a loop
        ch <- true 
}() 

这是一个简单的示例(https://play.golang.org/p/2anhrbrhlrv)

buf := bytes.NewBufferString("0123456789")
r := make([]byte, 3)
n, err := buf.Read(r)
fmt.Println(string(r), n, err)
// Output: 012 3 <nil>

使用io.Reader时使用给定切片的大小。如果您会在代码中记录n个变量,则不会读取整个文件。Goroutine之外的选择语句在错误的位置。

go func() {
    a := make([]byte, 1024)
    for {
        select {
        case <-quit:
            result <- []byte{}
            return
        default:
            _, err = self.reader.Read(buf)
            if err == io.EOF {
                result <- a
                return
            }
        }
    }
}()

但是还有更多!您要实现io.Reader接口。调用Read()方法直到文件结束之前,您不应该在此处启动Goroutine,因为您只会读取文件的块。此外,read()方法中的超时无济于事,因为该超时可适用于每个呼叫,而不是整个文件。

除了 @apxp关于循环读取的观点外,您还可以使用1个字节的缓冲区大小,这样您就永远不会屏蔽,只要有数据可读取。

与外部资源交互时,任何事情都可能发生。任何给定的IO.Reader实现都可以永远阻止。在这里,我会为你写一个...

type BlockingReader struct{}
func (BlockingReader) Read(b []byte) (int, error) {
    <-make(chan struct{})
    return 0, nil
}

请记住,任何人都可以实现接口,因此您不能做出任何假设,即它的行为将像*os.File或任何其他标准库io.Reader。除了上述我的asinine编码外,io.Reader还可以合法地连接到可以永远阻止的资源。

您无法杀死Gorountines,因此,如果io.Reader真正阻止了封锁的Goroutine,则将继续消耗资源,直到您的应用程序终止为止。但是,这应该不是问题,而被阻止的goroutine不会以资源的方式消耗太多,只要您不盲目地重试封底读物,就可以很好地消耗。

相关内容

  • 没有找到相关文章

最新更新