簡體   English   中英

FILE *和文件描述符的讀/寫性能

[英]FILE* and file descriptor read/write performance

使用FILE*file descriptor API處理本地磁盤文件二進制數據讀寫有什么性能影響? 哪一種方式比另一種方式具有任何優勢?

在性能方面, fread()read()要比另一個更好嗎? 他們的行為,緩存或系統資源使用情況如何不同?

在性能方面, fwrite()write()要比另一個好嗎? 他們的行為,緩存或系統資源使用情況如何不同?

readwrite的系統調用:因此它們在用戶空間緩沖。 您在那里提交的所有內容都將直接進入內核。 底層文件系統可能具有內部緩沖,但這里最大的性能影響將來自每次調用時更改為內核空間。

freadfwrite是用戶空間庫調用,默認情況下是緩沖的。 因此,這些將把您的訪問組合在一起,以使它們更快(理論上)。

親自試一試: read一次從文件中一個字節,然后fread同時從它的一個字節。 后者應該快4000倍。

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/resource.h>

int main() {
    struct rusage usage_start, usage_end;

    getrusage(RUSAGE_SELF, &usage_start);

    int fd = open("/dev/zero", O_RDONLY);

    int i = 0x400 * 0x400; // 1 MB

    char c;

    while (i--)
        read(fd, &c, 1);

    close(fd);

    getrusage(RUSAGE_SELF, &usage_end);

    printf("Time used by reading 1MiB: %zu user, %zu system.\n", ((usage_end.ru_utime.tv_sec - usage_start.ru_utime.tv_sec)* 1000000) + usage_end.ru_utime.tv_usec - usage_start.ru_utime.tv_usec, ((usage_end.ru_stime.tv_sec - usage_start.ru_stime.tv_sec)* 1000000) + usage_end.ru_stime.tv_usec - usage_start.ru_stime.tv_usec);

    getrusage(RUSAGE_SELF, &usage_start);

    FILE * fp = fopen("/dev/zero", "r");

    i = 0x400 * 0x400; // 1 MB

    while (i--)
        fread(&c, 1, 1, fp);

    fclose(fp);

    getrusage(RUSAGE_SELF, &usage_end);

    printf("Time used by freading 1MiB: %zu user, %zu system.\n", ((usage_end.ru_utime.tv_sec - usage_start.ru_utime.tv_sec)* 1000000) + usage_end.ru_utime.tv_usec - usage_start.ru_utime.tv_usec, ((usage_end.ru_stime.tv_sec - usage_start.ru_stime.tv_sec)* 1000000) + usage_end.ru_stime.tv_usec - usage_start.ru_stime.tv_usec);

    return 0;
}

在我的OS X上返回:

Time used by reading 1MiB: 103855 user, 442698 system.
Time used by freading 1MiB: 20146 user, 256 system.

stdio函數只是圍繞適當的系統調用包裝優化代碼。

這是程序的一個strace

getrusage(RUSAGE_SELF, {ru_utime={0, 0}, ru_stime={0, 0}, ...}) = 0
open("/dev/zero", O_RDONLY)             = 3

然后跟隨1048576次

read(3, "\0", 1)                        = 1

其余的:

close(3)                                = 0
getrusage(RUSAGE_SELF, {ru_utime={0, 200000}, ru_stime={5, 460000}, ...}) = 0

這是fopen一部分:

fstat(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2aaaaaaae000

getrusage(RUSAGE_SELF, {ru_utime={0, 200000}, ru_stime={5, 460000}, ...}) = 0
// ...
open("/dev/zero", O_RDONLY)             = 3
fstat(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(1, 5), ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fffffffb050) = -1 ENOTTY (Inappropriate ioctl for device)
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2aaaaaaaf000

現在256次:

read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096

請注意,雖然我逐字節讀取,但stdio庫一次stdio獲取一頁文件內容。

其余大部分是釋放:

close(3)                                = 0
munmap(0x2aaaaaaaf000, 4096)            = 0
getrusage(RUSAGE_SELF, {ru_utime={0, 230000}, ru_stime={5, 460000}, ...}) = 0
write(1, "Time used by reading 1MiB: 20000"..., 106Time used by reading 1MiB: 200000 user, 5460000 system.
Time used by freading 1MiB: 30000 user, 0 system.
) = 106
exit_group(0)                           = ?

關於訪問磁盤上的文件,答案是:這取決於。 較高級別的函數可以啟用緩沖,這可以減少物理I / O的數量,這意味着可以減少進行的read() / write()調用的實際數量(fread()調用read()來訪問磁盤)等)。

因此,在啟用緩沖的情況下,高級功能的優勢在於,您通常會看到更好的性能,而無需考慮您正在做什么。 低級功能的優勢在於,如果您知道應用程序將如何執行操作,則可以通過直接管理自己的緩沖來提高性能。

我同意,fread / fwrite比讀/寫快,但是:

1)如果文件將被隨機訪問,則fwrite / fread無法如此有效地使用,並且大多數時候它們可能導致性能損失。

2)如果文件正在由另一個進程或線程共享,那么它將不會那么快並且無法使用,除非您每次寫入文件時都使用flush()命令,並且在這種情況下還提高了速度與寫命令至少相等地減小。 同樣,由於使用了fread命令,因為它使用其緩沖區讀取可能不會更新的數據,或者如果關心更新,則必須丟棄已讀取的內容以讀取新數據。

因此,這取決於。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM