Fork me on GitHub

版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://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包的实现原理

请我喝瓶饮料

微信支付码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注