我希望从std::in
中读取语法如下(它总是int
,int
,int
,char[]
/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工具,其唯一目的是计算行,单词和字符。