std:cin真的很慢
std::cin really slow
所以我试图为自己编写一个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(buffer,size),但没有任何改进。这很尴尬,是缓冲问题吗?我还试着一次获取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搞砸了时间。
要为标准I/O流对象获得良好性能,首先要做的事情是关闭与标准C流对象的同步:
std::ios_base::sync_with_stdio(false);
一旦你做到了这一点,你应该会得到更好的表现。不过,你是否能取得好成绩是另一个问题。
由于有些人声称cat
在内部会做什么很有趣,以下是将一个流复制到另一个流的最快方法:
std::cout << std::cin.rdbuf();
如果你能正确地将D_2从一个流std::copy()
到另一个流,我会很高兴,但这对大多数I/O流实现来说都不太好:
std::copy(std::istreambuf_iterator<char>(std::cin), std::istreambuf_iterator<char>(),
std::ostreambuf_iterator<char>(std::cout));
我希望我最终能做到最好。。。
这正是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);
}
简而言之,如果您的需求是对输入执行逐行分析,那么您将不得不为使用格式化输入付出一些代价。另一方面,如果您需要执行逐字节的分析,那么您可以使用未格式化的输入,并且速度更快。
如果你真的想用stdin获得更好的性能,你应该尝试使用纯C.
vector<char> line(0x1000);
while(!feof(stdin))
fgets(&line.front(), line.size(), stdin);
我认为更快的解决方案将基于sendfile
- C++中的cin.ignore()函数不适用于整个流
- 在while循环中输入带有std::cin的字符串后,控制台会输出大量胡言乱语
- 在决定是通过参考还是通过价值时,尺寸真的是一个问题吗
- Problems with std::cin.fail()
- 由cin中的字符串中未捕获空白引起的分割错误
- 在C++中使用Cin,我如何在1行中输入
- 将 cin 限制为只有一个
- 字节真的是最小可寻址单元吗
- cin >> int 给定一个字符串将 int 赋值为 0
- istream std::cin如何修改自定义istream缓冲区
- C++ 将 CIN 值存储到任何类型的数组中
- 为什么无论你输入什么,这"while(cin.get(str,3))"只运行一次?
- 如果我真的真的想从 STL 容器继承,并且我继承构造函数并删除新运算符,会发生什么?
- 如何在 std::vector 中找到<bool>哪些索引是真的?
- cin 的十进制输入验证?
- std::string 的对象真的可以移动吗?
- Turbo C++ cin() 不能与 gets() 一起使用
- 使用 cin 时接受小数点后的 2 位数字
- 在 std::getline 和 std::cin 期间卡在循环中
- std:cin真的很慢