写入Linux管道比文件快,但在内核级别,为什么



我关注的是写入文件的速度与管道的速度。请看下面的代码,它会写入文件句柄,除非有命令行参数,否则它会写入管道:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <chrono>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;

void do_write(int fd)
{
const char* data = "Hello world!";
int to_write = strlen(data), total_written = 0;

int x = 0;
auto start = chrono::high_resolution_clock::now();

while (x < 50000)
{       
int written = 0;
while (written != to_write)
{
written += write(fd, data + written, to_write - written);
}
total_written += written;
++x;
}
auto end = chrono::high_resolution_clock::now();
auto diff = end - start;

cout << "Total bytes written: " <<  total_written << " in " << chrono::duration<double, milli>(diff).count() 
<< " milliseconds, " << endl;
}

int main(int argc, char *argv[])
{  
//
// Write to file if we have not specified any extra argument
//

if (argc == 1)
{   
{   
int fd = open("test.txt", O_WRONLY | O_TRUNC | O_CREAT, 0655);
if (fd == -1) return -1;
do_write(fd);
}   

return 0;
}

//
// Otherwise, write to pipe
//
int the_pipe[2];
if (pipe(the_pipe) == -1) return -1;

pid_t child = fork();
switch (child)
{
case -1:
{
return -1;
}
case 0:
{
char buf[128];
int bytes_read = 0, total_read = 0;
close(the_pipe[1]);
while (true)
{
if ((bytes_read = read(the_pipe[0], buf, 128)) == 0)
break;
total_read += bytes_read;
}
cout << "Child: Total bytes read: " << total_read << endl;
break;
}
default:
{
close(the_pipe[0]);
do_write(the_pipe[1]);
break;
}
}
return 0;
}

这是我的输出:

$ time ./LinuxFlushTest pipe
Total bytes written: 600000 in 59.6544 milliseconds,
real    0m0.064s
user    0m0.020s
sys     0m0.040s
Child: Total bytes read: 600000
$ time ./LinuxFlushTest
Total bytes written: 600000 in 154.367 milliseconds,
real    0m0.159s
user    0m0.028s
sys     0m0.132s

您可以看到,从time输出和我的C++代码计时到管道的写入速度都比文件快得多。

现在,据我所知,当我们调用write()时,数据将被复制到内核缓冲区,此时pdflush风格的线程实际上会将其从页面缓存刷新到底层文件我没有在代码中强制执行此刷新操作,因此没有磁盘查找延迟

但我不知道的是(似乎也找不到:是的,我看过内核代码,但迷失在其中,所以没有像"请看代码"这样的评论(,在向管道写入时会发生什么不同:它不仅仅是内核中孩子可以读取的内存块吗?在这种情况下,为什么它比基本相同的文件写入过程快得多?

现在,据我所知,当我们调用write()时,数据将被复制到内核缓冲区,此时pdflush风格的线程将实际上是将它从页面缓存刷新到底层文件我是没有在我的代码中强制执行此刷新,因此没有磁盘查找延迟

你似乎有一些误解,包括:

  1. 您不必为内核显式地执行任何操作,即可将写入的数据刷新到底层输出设备。它可能会在一段时间内缓冲内存中的部分甚至全部数据,但可以预料的是,即使没有用户空间的明确指令,内核也会在某个时刻写入数据。这可能会受到写入数据量的影响,在您的案例中,写入数据量似乎相当大,为600000字节。

  2. 磁盘查找并不是磁盘I/O(相对(缓慢的唯一原因。即使是使用SSD的I/O也比仅使用内存的数据传输慢。

  3. 除其他外,标准文件系统不仅仅是一个扁平的字节跨度。即使没有任何移动部件,仍然必须与文件系统的数据结构交互,以确定在哪里写入,并在写入后更新它。通常希望该信息能够迅速对其他进程可见,因此而不是通常被无限期推迟。

但我不知道的是[…]在向管道:它不只是内核中某个地方的一块内存吗孩子能从中阅读吗?

还有更多,但这是一个合理的第一近似值。

既然如此,为什么它比写入文件的基本相同过程?

因为写入常规文件基本上是完全相同的。还有很多。

最新更新