为什么'dd'能够比使用ifstream的程序更快地读取管道?

时间:2013-03-27 18:20:02

标签: c++ linux pipe ifstream

我有两个程序通过linux管道(命名或其他方式)将数据传递给对方。我需要在两个程序之间达到~2600 MB / s的传输速率,但目前看到的速度约为~2200 MB / s。但是,我发现如果用'dd'代替我的第二个进程,传输速率会跳到3000 MB / s以上。有什么关于我的程序从管道中读取的方式是什么,效率低于'dd'的方式?我该怎么做才能提高吞吐量? 'ifstream'本身是否比从管道中读取二进制数据的其他方法慢?

总结两种情况:

  

情景1:

     

计划1 - > [命名管道] - >计划2

     

产量〜2200 MB / s传输速率

     

Scenario2:

     

计划1 - > [命名管道] - > '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(),这没什么用。

2 个答案:

答案 0 :(得分:3)

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

计划1(2500 MB / 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(3100 MB / 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);
    }
}

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

编辑:我刚刚测试了下面的程序3,它可以使用ifstream并以3000 MB / s的速度运行。因此,使用ifstream而不是'read()'会导致性能下降非常轻微。比使用std :: vector的命中要少得多。

计划3(3000 MB / 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,让我知道这个。

答案 1 :(得分:1)

此代码使用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()中的方法。