std :: cin真的很慢

时间:2012-01-26 20:47:31

标签: c++ pipeline cout cin

所以我试图给自己写一个linux管道的命令。可以把它想象成gnu'cat'或'sed'的副本,它从stdin获取输入,做一些处理并写入stdout。

我最初编写了一个AWK脚本,但想要更多性能,所以我使用了以下c ++代码:

std::string crtLine;
crtLine.reserve(1000);
while (true)
{
    std::getline(std::cin, crtLine);
    if (!std::cin) // failbit (EOF immediately found) or badbit (I/O error)
        break;

    std::cout << crtLine << "\n";
}

这正是cat(没有任何参数)。 事实证明,这个程序和它的awk一样慢,并且远没有cat那么快。

在1GB文件上进行测试:

$time cat 'file' | cat | wc -l
real    0m0.771s

$time cat 'file' | filter-range.sh | wc -l
real    0m44.267s

而不是getline(istream,string)我尝试了cin.getline(缓冲区,大小),但没有改进。这很令人尴尬,这是一个缓冲问题吗?我也试过一次取100KB而不是一行,没有帮助!有什么想法吗?

编辑: 你们所说的是有道理的,但罪魁祸首不是字符串构建/复制,也不是扫描新行。 (也不是缓冲区的大小)。看看这两个程序:

char buf[200];
while (fgets(buf, 200, stdin))
    std::cout << buf;

$time cat 'file' | ./FilterRange > /dev/null
real    0m3.276s




char buf[200];
while (std::cin.getline(buf, 200))
    std::cout << buf << "\n";

$time cat 'file' | ./FilterRange > /dev/null
real    0m55.031s

它们都没有操纵字符串,而且它们都进行换行扫描,但是其中一个比另一个慢17倍。它们的区别仅在于使用cin。 我想我们可以得出结论,cin搞定了时机。

4 个答案:

答案 0 :(得分:12)

为了获得标准I / O流对象的良好性能,您想要做的第一次事情,它会关闭与标准C流对象的同步:

std::ios_base::sync_with_stdio(false);

完成此操作后,您应该获得更好的性能。但是,你是否获得了良好的表现是一个不同的问题。

由于有些人声称有关cat内部会做什么的有趣事情,这里应该是将一个流复制到另一个流的最快方法:

std::cout << std::cin.rdbuf();

我很乐意,如果你能够std::copy()一个流到另一个流,但这对大多数I / O流实现都不会很好:

std::copy(std::istreambuf_iterator<char>(std::cin), std::istreambuf_iterator<char>(),
          std::ostreambuf_iterator<char>(std::cout));

我希望最终达到最佳状态......

答案 1 :(得分:4)

  

这正是cat(没有任何参数)。

不是真的。这与/ bin / cat具有完全相同的效果,但它不使用相同的方法。

/bin/cat看起来更像是这样:

while( (readSize = read(inFd, buffer, sizeof buffer)) > 0)
  write(outFd, buffer, readSize);

请注意/bin/cat不对其输入进行处理。它不会构建std::string,它不会扫描\n,它只会进行一次系统调用。

另一方面,您的程序构建string,制作副本,扫描\n等等。

这个小而完整的程序比/ bin / cat慢了2-3个数量级:

#include <string>
#include <iostream>

int main (int ac, char **av) {
  std::string crtLine;
  crtLine.reserve(1000);
  while(std::getline(std::cin, crtLine)) {
    std::cout << crtLine << "\n";
  }
}

我这样定时:

$ time ./x < inputFile > /dev/null
$ time /bin/cat < inputFile > /dev/null

<小时/> 的修改 该程序在/ bin / cat的性能的50%范围内:

#include <string>
#include <iostream>
#include <vector>

int main (int ac, char **av) {
  std::vector<char> v(4096);
  do {
    std::cin.read(&v[0], v.size());
    std::cout.write(&v[0], std::cin.gcount());
  } while(std::cin);
}

简而言之,如果您的要求是对输入执行逐行分析,那么您将需要付出一些代价才能使用格式化输入。另一方面,如果您需要执行逐字节分析,那么您可以使用未格式化的输入并加快速度。

答案 2 :(得分:0)

如果你真的想用stdin获得更好的性能,你应该尝试使用纯C。

vector<char> line(0x1000);
while(!feof(stdin))
    fgets(&line.front(), line.size(), stdin);

答案 3 :(得分:0)

我认为更快的解决方案将基于sendfile