为什么使用 syscall.O_DIRECT 标志写入文件会使写入文件变慢?

我有一小段代码,名为test.go. 它在执行两次写入时计算时间(ns),将相同的字节片写入 2 个文件,一个带有标志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倍:(


结果:


sysW1: 1107377

sysW2: 37155

为什么?我认为使用 syscall.O_DIRECT 进行编写会减少复制并且会更快,但现在证明它要慢得多。请帮我解释一下:(


PX:我不会提供游乐场链接,因为在游乐场运行程序时由于某些原因总是返回0。


HUH函数
浏览 166回答 1
1回答

白衣染霜花

O_DIRECT没有按照你的想法去做。虽然它减少了内存复制(因为它不会在复制到设备驱动程序之前复制到缓存),但这并不能提高性能。文件系统缓存确保系统调用可以在数据写入设备之前尽早返回,并缓冲数据以更大的块发送数据。使用O_DIRECT,系统调用会一直等待,直到数据完全传输到设备。从呼叫的手册页open:O_DIRECT(自 Linux 2.4.10 起)尽量减少进出此文件的 I/O 的缓存效应。 通常这会降低性能,但在特殊情况下很有用,例如当应用程序进行自己的缓存时。文件 I/O 直接从用户空间缓冲区完成。O_DIRECT标志本身努力同步传输数据,但不保证O_SYNC数据和必要的元数据被传输。另请参阅:O_DIRECT 的真正含义是什么?使用后无需手动释放缓存。缓存被 Linux 内核视为可用的可用内存。如果进程需要缓存占用的内存,内核将在此时刷新/释放缓存。缓存不会“用完”内存。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go