前言
大家都知道写文件时数据流转的顺序是
用户空间文件缓冲区 -> 内核空间文件缓冲区 -> 内核空间IO队列
默认的ANSI C库,对用户空间文件缓冲区有三种方式
- 全缓冲
- 行缓冲
- 无缓冲
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.gowrite2.go
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开启用户空间的文件读写缓冲区。