我有一小段名为test.go
的代码。它计算两次写入时的时间(ns),将相同的字节片写入两个文件,一个带有syscall.O_DIRECT
标志,另一个没有。
代码如下:
package main;
import (
"os"
"time"
"fmt"
"strconv"
"bytes"
"syscall"
// "os/exec"
)
func main() {
num, _ := strconv.Atoi(os.Args[1]);
writeContent:= bytes.Repeat( ([]byte)("1"), num );
t1:= time.Now().UnixNano();
fd1, err := syscall.Open("abc.txt", syscall.O_WRONLY | syscall.O_DIRECT | syscall.O_TRUNC, 0);
syscall.Write(fd1, writeContent);
if err != nil {panic(err);}
t2:= time.Now().UnixNano();
fmt.Println("sysW1:", t2-t1);
t1= time.Now().UnixNano();
fd2, err := syscall.Open("abc.txt", syscall.O_WRONLY | syscall.O_TRUNC, 0);
syscall.Write(fd2, writeContent);
if err != nil {panic(err);}
t2= time.Now().UnixNano();
fmt.Println("sysW2:", t2-t1);
}
程序在linux命令行中运行如下:(用go build ./test.go
编译后)
./test 1024
我期望用syscall.O_DIRECT
标志写文件会更快,但结果表明,用syscall.O_DIRECT
标志写文件大约是30比不写慢1倍:(
结果:
sysW1: 1107377
sysW2: 37155
为什么?我用系统调用学习写作。O_DIRECT做的复制更少,本来会更快,但现在却慢了很多。请帮我解释一下:(
PX:由于某些原因,在操场上运行程序时,结果总是0,因此我将不提供操场链接。
O_DIRECT
不是你想的那样。虽然它做了更少的内存复制(因为它在复制到设备驱动程序之前不会复制到缓存),但这并没有给你带来性能提升。
文件系统缓存确保系统调用可以在数据写入设备之前尽早返回,并缓冲数据以更大的块发送数据。
对于O_DIRECT
,系统调用等待,直到数据完全传输到设备。
open
调用的手册页:
O_DIRECT
(自Linux 2.4.10起)尽量减少I/O对缓存的影响文件。通常这会降低性能,但事实确实如此在特殊情况下很有用,比如应用程序它们自己的缓存。文件I/O是直接从/到文件的用户空间缓冲区。
O_DIRECT
标志本身就是一个努力同步传输数据,但没有给出O_SYNC
标志保证数据是必需的元数据被传输。
参见:O_DIRECT的真正含义是什么?
您不需要在使用缓存后手动释放缓存。Linux内核认为缓存是空闲的可用内存。如果进程需要的内存被缓存占用,内核将在此时刷新/释放缓存。缓存没有"用完"。记忆。