从输入中读取行



我希望从std::in中读取语法如下(它总是intintintchar[]/str)。将数据解析为int array[3]和字符串或char数组的最快方法是什么。

#NumberOfLines(i.e.10000000)
1,2,2,'abc'
2,2,2,'abcd'
1,2,3,'ab'
...1M+ to 10M+ more lines, always in the form of (int,int,int,str)

目前,我正在做一些类似的事情。

//unsync stdio
std::ios_base::sync_with_stdio (false);
std::cin.tie(NULL);
//read from cin
for(i in amount of lines in stdin){
getline(cin,str);
if(i<3){
int commaindex = str.find(',');
string substring = str.substr(0,commaindex);
array[i]=atoi(substring.c_str());
str.erase(0,commaindex+1)
}else{
label = str;
}
//assign array and label to other stuff and do other stuff, repeat
}

我对C++很陌生,最近学习了Visual Studio的分析,但不是最好的解释它。IO 占用 68.2%,内核占用 15.8% 的 CPU 使用率。getline()覆盖了 35.66% 的已用包含时间。

有什么方法可以做一些类似于一次读取大块的事情来避免调用getline()那么多?有人告诉我fgets()要快得多,但是,当我无法预测要指定的字符数时,我不确定如何使用它。

我尝试按如下方式使用scanf,但它比getline方法慢。也使用过"字符串流",但这非常慢。

scanf("%i,%i,%i,%s",&array[0],&array[1],&array[2],str);

此外,如果重要,它会在可用内存不足的服务器上运行。我认为将整个输入读取到缓冲区是不可行的? 谢谢!

更新:使用@ted-lyngmo方法,收集了以下结果。

time wc datafile

real    4m53.506s
user    4m14.219s
sys     0m36.781s

time ./a.out < datafile

real    2m50.657s
user    1m55.469s
sys     0m54.422s

time ./a.out datafile

real    2m40.367s
user    1m53.523s
sys     0m53.234s

您可以使用std::from_chars(并reserve()文件中的大致行数,例如,如果您将值存储在vector中)。我还建议添加对直接从文件读取的支持。从程序打开的文件读取(至少对我来说)比从std::cin读取(即使使用sync_with_stdio(false))更快。

例:

#include <algorithm> // std::for_each
#include <cctype>    // std::isspace
#include <charconv>  // std::from_chars
#include <cstdio>    // std::perror
#include <fstream>
#include <iostream>
#include <iterator>  // std::istream_iterator
#include <limits>    // std::numeric_limits
struct foo {
int a[3];
std::string s;
};
std::istream& operator>>(std::istream& is, foo& f) {
if(std::getline(is, f.s)) {
std::from_chars_result fcr{f.s.data(), {}};
const char* end = f.s.data() + f.s.size();
// extract the numbers
for(unsigned i = 0; i < 3 && fcr.ptr < end; ++i) {
fcr = std::from_chars(fcr.ptr, end, f.a[i]);
if(fcr.ec != std::errc{}) {
is.setstate(std::ios::failbit);
return is;
}
// find next non-whitespace
do ++fcr.ptr;
while(fcr.ptr < end &&
std::isspace(static_cast<unsigned char>(*fcr.ptr)));
}
// extract the string
if(++fcr.ptr < end)
f.s = std::string(fcr.ptr, end - 1);
else
is.setstate(std::ios::failbit);
}
return is;
}
std::ostream& operator<<(std::ostream& os, const foo& f) {
for(int i = 0; i < 3; ++i) {
os << f.a[i] << ',';
}
return os << ''' << f.s << "'n";
}
int main(int argc, char* argv[]) {
std::ifstream ifs;
if(argc >= 2) {
ifs.open(argv[1]); // if a filename is given as argument
if(!ifs) {
std::perror(argv[1]);
return 1;
}
} else {
std::ios_base::sync_with_stdio(false);
std::cin.tie(nullptr);
}
std::istream& is = argc >= 2 ? ifs : std::cin;
// ignore the first line - it's of no use in this demo
is.ignore(std::numeric_limits<std::streamsize>::max(), 'n');
// read all `foo`s from the stream
std::uintmax_t co = 0;
std::for_each(std::istream_iterator<foo>(is), std::istream_iterator<foo>(),
[&co](const foo& f) {
// Process each foo here
// Just counting them for demo purposes:
++co;
});
std::cout << co << 'n';
}

我的测试在一个包含 1'000'000'000 行的文件上运行,内容如下所示:

2,2,2,'abcd'
2, 2,2,'abcd'
2, 2, 2,'abcd'
2, 2, 2, 'abcd'

Unixtime wc datafile

1000000000  2500000000 14500000000 datafile
real    1m53.440s
user    1m48.001s
sys     0m3.215s

time ./my_from_chars_prog datafile

1000000000
real    1m43.471s
user    1m28.247s
sys     0m5.622s

从这个比较中,我认为可以看到my_from_chars_prog能够非常快速地成功解析所有条目。它始终比wc更快 - 一个标准的Unix工具,其唯一目的是计算行,单词和字符。

最新更新