从输入中读取行

Reading lines from input

我希望从 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%,内核占 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 工具,其唯一目的是计算行数、单词和字符数。