douyihuaimao733955 2017-12-01 03:53
浏览 56

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

I know there is a function called SetReadDeadline that can set a timeout in socket(conn.net) reading, while io.Read not. There is a way that starts another routine as a timer to solve this problem, but it brings another problem that the reader routine(io.Read) still block:

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 
} 

This question is similar in this post, but the answer is unclear. Do you guys have any good idea to solve this problem?

  • 写回答

3条回答 默认 最新

  • dongliantong3229 2018-08-09 13:30
    关注

    Your mistake here is something different:

    When you read from the reader you just read one time and that is wrong:

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

    Here is a simple example (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>
    

    The size of the given slice is used when using the io.Reader. If you would log the n variable in your code you would see, that not the whole file is read. The select statement outside of your goroutine is at the wrong place.

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

    But there is something more! You want to implement the io.Reader interface. After the Read() method is called until the file ends you should not start a goroutine in here, because you just read chunks of the file. Also the timeout inside the Read() method doesn't help, because that timeout works for each call and not for the whole file.

    评论

报告相同问题?