doufu6130 2016-05-24 10:36
浏览 25

从ajax请求并发写入文件

I want to write requests to one file from some ajax script. The problem arises when there will be many of those in a second and writing to file will take more time than the break between requests, and when there will be two requests at the same time.

How could I solve this?

I've came up using mutex, like:

var mu sync.Mutex
func writeToFile() {
    mu.Lock()
    defer mu.Unlock()
    // write to file
}

But it makes the whole thing synchronous and I don't really know what happens when there are two requests at the same time. And it still does not lock the file itself.

Uh, what's the proper way to do this?

  • 写回答

1条回答 默认 最新

  • dqk77945 2016-05-24 11:41
    关注

    You only need to make writing to the file "sequential", meaning don't allow 2 concurrent goroutines to write to the file. Yes, if you use locking in the writeToFile() function, serving your ajax requests may become (partially) sequential too.

    What I suggest is open the file once, when your application starts. And designate a single goroutine which will be responsible writing to the file, no other goroutines should do it.

    And use a buffered channel to send data that should be written to the file. This will make serving ajax requests non-blocking, and still the file will not be written concurrently / parallel.

    Note that this way ajax requests won't even have to wait while the data is actually written to the file (faster response time). This may or may not be a problem. For example if later writing fails, your ajax response might already be committed => no chance to signal failure to the client.

    Example how to do it:

    var (
        f      *os.File
        datach = make(chan []byte, 100) // Buffered channel
    )
    
    func init() {
        // Open file for appending (create if doesn't exist)
        var err error
        f, err = os.OpenFile("data.txt", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0666)
        if err != nil {
            panic(err)
        }
    
        // Start goroutine which writes to the file
        go writeToFile()
    }
    
    func writeToFile() {
        // Loop through any data that needs to be written:
        for data := range datach {
            if _, err := f.Write(data); err != nil {
                // handle error!
            }
        }
        // We get here if datach is closed: shutdown
        f.Close()
    }
    
    func ajaxHandler(w http.ResponseWriter, r *http.Request) {
        // Assmeble data that needs to be written (appended) to the file
        data := []byte{1, 2, 3}
        // And send it:
        datach <- data
    }
    

    To gracefully exit from the app, you should close the datach channel: when it's closed, the loop in the writeToFile() will terminate, and the file will be closed (flushing any cached data, releasing OS resources).

    If you want to write text to the file, you may declare the data channel like this:

    var datach = make(chan string, 100) // Buffered channel
    

    And you may use File.WriteString() to write it to the file:

    if _, err := f.WriteString(data); err != nil {
        // handle error!
    }
    
    评论

报告相同问题?

悬赏问题

  • ¥15 用hfss做微带贴片阵列天线的时候分析设置有问题
  • ¥50 我撰写的python爬虫爬不了 要爬的网址有反爬机制
  • ¥15 Centos / PETSc / PETGEM
  • ¥15 centos7.9 IPv6端口telnet和端口监控问题
  • ¥120 计算机网络的新校区组网设计
  • ¥20 完全没有学习过GAN,看了CSDN的一篇文章,里面有代码但是完全不知道如何操作
  • ¥15 使用ue5插件narrative时如何切换关卡也保存叙事任务记录
  • ¥20 海浪数据 南海地区海况数据,波浪数据
  • ¥20 软件测试决策法疑问求解答
  • ¥15 win11 23H2删除推荐的项目,支持注册表等