Fork me on GitHub

版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | http://vearne.cc

前言

大家都知道写文件时数据流转的顺序是

用户空间文件缓冲区 -> 内核空间文件缓冲区 -> 内核空间IO队列

29075379_138130814277tC.jpg-63.6kB

默认的ANSI C库,对用户空间文件缓冲区有三种方式

  • 全缓冲
  • 行缓冲
  • 无缓冲

难道Golang没有?笔者不敢断定,但有以下的对比试验或许能说明些问题
write.go

package main

import (
    "os"
    "log"
    "time"
)

func main() {
    file, err := os.OpenFile("test.txt",
        os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
    if err != nil {
        log.Fatal(err)
    }
    for i := 0; i < 1000; i++ {
        time.Sleep(2 * time.Second)
        file.Write([]byte("xxxx"))
    }
    file.Close()
}

write2.go
write2.go 使用了标准库提供的bufio, 给写文件增加了4096byte的缓冲区

package main

import (
    "os"
    "log"
    "time"
    "bufio"
)


func main(){
    file, err := os.OpenFile("test.txt",
        os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)
    writer := bufio.NewWriterSize(file, 4096)
    if err!= nil{
        log.Fatal(err)
    }
    for i:=0;i<1000;i++{
        time.Sleep(2 * time.Second)
        writer.Write([]byte("xxxx"))
    }
    writer.Flush()
    file.Close()
}

使用strace跟踪系统调用, 在没有使用bufio的情况如下

) = -1 ETIMEDOUT (Connection timed out)
futex(0x53a1d0, FUTEX_WAKE, 1)          = 1
futex(0xc420072148, FUTEX_WAKE, 1)      = 1
write(3, "xxxx", 4)                     = 4
futex(0x53cb00, FUTEX_WAIT, 0, {1, 999998648}


) = -1 ETIMEDOUT (Connection timed out)
futex(0x53a1d0, FUTEX_WAKE, 1)          = 1
futex(0xc420046948, FUTEX_WAKE, 1)      = 1
write(3, "xxxx", 4)                     = 4
futex(0xc420046948, FUTEX_WAKE, 1)      = 1
futex(0x53cb80, FUTEX_WAIT, 0, {1, 999933913}

每次调用writer.Write([]byte(“xxxx”)) 均有系统调用write(3, “xxxx”, 4) 被触发

使用bufio的情况如下

) = -1 ETIMEDOUT (Connection timed out)
futex(0x53c290, FUTEX_WAKE, 1)          = 1
futex(0xc42006a148, FUTEX_WAKE, 1)      = 1
futex(0x53ebc0, FUTEX_WAIT, 0, {2, 112782}

) = -1 ETIMEDOUT (Connection timed out)
futex(0x53c290, FUTEX_WAKE, 1)          = 1
futex(0xc42006a148, FUTEX_WAKE, 1)      = 1
futex(0xc42006a148, FUTEX_WAKE, 1)      = 1
futex(0x53eb40, FUTEX_WAIT, 0, {1, 999998437}

在用户空间的文件写缓冲区没有写满前,没有write()系统调用被触发,可见使用用户空间文件缓冲区是有效的。

总结

系统调用的开销很高,如果能减少一部分系统调用能够有效的提高服务的吞吐能力。看来以后再读写文件时,很有必要多使用bufio开启用户空间的文件读写缓冲区。

参考资料

  1. golang中bufio包的实现原理

如果我的文章对你有帮助,你可以给我打赏以促使我拿出更多的时间和精力来分享我的经验和思考总结。

微信支付码

发表评论

电子邮件地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据