Reading from file without locking it

后端 未结 2 1202
耶瑟儿~
耶瑟儿~ 2021-01-15 09:39

I constantly write to one file some data everytime requests come in. I also want to parse this file and read from it sometimes. How can I do this reading if the file is cons

相关标签:
2条回答
  • 2021-01-15 10:30

    so you want Read & Write file without locking it,
    Stateful Goroutines and channels are the solution:
    one Stateful Goroutine manages the read and write requests.
    working sample code:

    package main
    
    import "os"
    import "fmt"
    import "sync"
    
    type Buffer struct {
        buf []byte
        off int64
    }
    
    var wg sync.WaitGroup
    
    func main() {
        wr := make(chan *Buffer)
        rq := make(chan *Buffer)
        rd := make(chan *Buffer)
        wg.Add(1)
        go manage("file.bin", wr, rq, rd)
    
        wr <- &Buffer{buf: []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, off: 0}            //write
        wr <- &Buffer{buf: []byte{10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, off: 10} //write
    
        rq <- &Buffer{buf: make([]byte, 20), off: 0} //request to read
        b := <-rd                                    //read
        fmt.Println("read:", b)
        //read: &{[1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19] 0}
    
        rq <- &Buffer{buf: nil, off: -1} // exit
        wg.Wait()
        fmt.Println("Bye") //Bye
    }
    
    func manage(filename string, wr, rq, rd chan *Buffer) {
        f, e := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
        if e != nil {
            panic(e.Error())
        }
        defer f.Close()
        for {
            select {
            case b := <-wr:
                f.WriteAt(b.buf, b.off)
            default:
            }
            select {
            case b := <-rq:
                if b.off == -1 {
                    wg.Done()
                    return
                }
                n, _ := f.ReadAt(b.buf, b.off)
                rd <- &Buffer{b.buf[1:n], b.off}
            default:
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-15 10:32

    You could make use of sync.RWMutex. Then:

    • When you need to read the file, call RLock(), read, then call RUnlock().
    • When you need to write to the file, call Lock(), write, then call Unlock().

    As long as you do that, you're ensuring that:

    • Only one goroutine will be writing to the file at any time.
    • If you try to read the file while it's being modified, the lock will wait until you finish writing before starting to read the file.
    • If you try to write to the file while it's being read, the lock will wait until you finish reading before starting to write.

    Here's a very little example:

    package sample
    
    import (
        "sync"
    )
    
    var fileMutex = new(sync.RWMutex)
    
    func readFile() {
        fileMutex.RLock()
        defer fileMutex.RUnlock()
    
        // Read the file. Don't modify it.
    }
    
    func writeFile() {
        fileMutex.Lock()
        defer fileMutex.Unlock()
    
        // Write to the file.
    }
    
    0 讨论(0)
提交回复
热议问题