c - FILE* 和文件描述符读/写性能

标签 c performance sockets file-io

使用 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 库正在一次一页地获取文件内容。

其余的主要是释放:

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)                           = ?

关于c - FILE* 和文件描述符读/写性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17524512/

相关文章:

c++ - C 使用文件中定义的变量

c - 如何在函数签名中使用匿名枚举声明函数?

android - 带有 setGroupSummary(true) 的通知在 Android N 中不可见

java - 使用socket编程将文件从android传输到pc

c - 如何为特定目的动态分配二维数组?

matlab - 多次使用 Polyval 函数的性能改进

arrays - 阵列访问/写入性能差异?

windows - 在 Win32 中,有没有办法测试套接字是否是非阻塞的?

通过套接字进行 Java 加密对象序列化

c - 特殊字符在 Linux 终端中显示不正确