所以我试图给自己写一个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搞定了时机。
答案 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