从输入中读取行
Reading lines from input
我希望从 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%,内核占 CPU 使用率的 15.8%。 getline()
占已用时间的 35.66%。
有什么方法可以做一些类似于一次读取大块的事情来避免调用 getline()
吗?有人告诉我 fgets()
快得多,但是,当我无法预测要指定的字符数时,我不确定如何使用它。
我尝试按如下方式使用 scanf
,但它比 getline
方法慢。也使用过 `stringstreams,但速度非常慢。
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'
Unix time 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 工具,其唯一目的是计算行数、单词和字符数。
我希望从 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%,内核占 CPU 使用率的 15.8%。 getline()
占已用时间的 35.66%。
有什么方法可以做一些类似于一次读取大块的事情来避免调用 getline()
吗?有人告诉我 fgets()
快得多,但是,当我无法预测要指定的字符数时,我不确定如何使用它。
我尝试按如下方式使用 scanf
,但它比 getline
方法慢。也使用过 `stringstreams,但速度非常慢。
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'
Unix time 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 工具,其唯一目的是计算行数、单词和字符数。