为什么可以'd '从管道读取比我自己的程序使用ifstream更快

Why can 'dd' read from a pipe faster than my own program using ifstream?

本文关键字:程序 自己的 我自己 更快 ifstream 管道 读取 为什么      更新时间:2023-10-16

我有两个程序,它们通过linux管道(命名的或其他的)相互传递数据。我需要在两个程序之间达到~2600 MB/s的传输速率,但目前看到的速率较慢,约为~2200 MB/s。然而,我发现如果我用"dd"代替我的第二个进程,传输速率会跳到3000 MB/s以上。我的程序从管道中读取数据的方式是否比"dd"的方式效率低?我可以做些什么来提高吞吐量?是否'ifstream'固有地比从管道读取二进制数据的其他方法慢?

总结两种场景:

场景1:

程序1 ->[命名管道]->程序2

传输速率~ 2200mb/s

Scenario2:

程序1 -> [named pipe] -> 'dd if=pipename of=/dev/null bs=8M'

产生~3000 MB/s的传输率。

下面是我的程序2当前从管道中读取的方式:
ifstream inputFile;
inputFile.open(inputFileName.c_str(), ios::in | ios::binary);
while (keepLooping)
{
    inputFile.read(&buffer[0], 8*1024*1024);
    bytesRead = inputFile.gcount();
    //Do something with data
}

更新:

我现在尝试使用'read(fd, &buffer[0], 8*1024*1024)'来代替istream,似乎显示出轻微的改善(但不如dd)

我也尝试使用stream->rdbuf()->sgetn(&buffer[0], 8*1024*1024)来代替stream->read(),但没有帮助。

差异似乎是由于使用了数组而不是std::vector,这一点我仍然很难相信。下面展示了我的两组代码进行比较。第一个可以以大约2500mb/s的速率从程序1中摄取。第二个可以以3100 MB/s的速率摄取。

程序1 (2500mb/s)

int main(int argc, char **argv)
{
    int fd = open("/tmp/fifo2", O_RDONLY);
    std::vector<char> buf(8*1024*1024);
    while(1)
    {
       read(fd, &buf[0], 8*1024*1024);
    }
}

程序2 (3100mb/s)

int main(int argc, char **argv)
{
    int fd = open("/tmp/fifo2", O_RDONLY);
    char buf[8*1024*1024];
    while(1)
    {
       read(fd, &buf[0], 8*1024*1024);
    }
}

都是使用-O3使用gcc版本4.4.6编译的。如果有人能解释这个原因,我会非常感兴趣(因为我理解std::vector基本上是一个数组的包装器)。

Edit:我刚刚测试了下面的程序3,它可以使用ifstream并以3000 MB/s的速度运行。因此,使用ifstream而不是'read()'似乎会导致非常轻微的性能下降。远小于使用std::vector.

程序3 (3000mb/s)

int main(int argc, char **argv)
{
    ifstream file("/tmp/fifo2", ios::in | ios::binary);
    char buf[8*1024*1024];
    while(1)
    {
       file.read(&buf[0], 32*1024);
    }
}

编辑2:

我修改了程序2的代码,使用malloc内存而不是堆栈上的内存,性能下降到与矢量性能匹配。谢谢ipc,让我知道这个

g++ -Ofast编译的代码:

int main(int argc, char *argv[])
{
  if (argc != 2) return -1;
  std::ifstream in(argv[1]);
  std::vector<char> buf(8*1024*1024);
  in.rdbuf()->pubsetbuf(&buf[0], buf.size());
  std::ios_base::sync_with_stdio(false);
  std::cout << in.rdbuf();
}

的性能一点也不差。

$ time <<this program>> <<big input file>> >/dev/null
0.20s user 3.50s system 9% cpu 40.548 total
$ time dd if=<<big input file>> bs=8M > /dev/null
0.01s user 3.84s system 9% cpu 40.786 total

您必须考虑std::coutstdout共享缓冲区,如果不关闭,这确实很耗时。因此,如果您想要速度并且不打算使用C的输入输出方法(无论如何都较慢),请调用std::ios_base::sync_with_stdio(false);

此外,对于c++中原始的和快速的输入/输出,使用streambuf的方法,rdbuf()获得。