首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从输入中读取行

从输入中读取行
EN

Stack Overflow用户
提问于 2021-09-12 09:29:14
回答 1查看 132关注 0票数 1

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

代码语言:javascript
复制
#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)

目前,我正在做的事情大致是。

代码语言:javascript
复制
//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方法慢。我也使用了` `stringstreams,但速度太慢了。

代码语言:javascript
复制
scanf("%i,%i,%i,%s",&array[0],&array[1],&array[2],str);

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

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

time wc datafile

代码语言:javascript
复制
real    4m53.506s
user    4m14.219s
sys     0m36.781s

time ./a.out < datafile

代码语言:javascript
复制
real    2m50.657s
user    1m55.469s
sys     0m54.422s

time ./a.out datafile

代码语言:javascript
复制
real    2m40.367s
user    1m53.523s
sys     0m53.234s
EN

Stack Overflow用户

回答已采纳

发布于 2021-09-12 10:11:48

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

示例:

代码语言:javascript
复制
#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行的文件上,内容如下:

代码语言:javascript
复制
2,2,2,'abcd'
2, 2,2,'abcd'
2, 2, 2,'abcd'
2, 2, 2, 'abcd'

Unix time wc datafile

代码语言:javascript
复制
1000000000  2500000000 14500000000 datafile

real    1m53.440s
user    1m48.001s
sys     0m3.215s

time ./my_from_chars_prog datafile

代码语言:javascript
复制
1000000000

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

从这个比较中,我认为可以看出my_from_chars_prog能够相当快地成功解析所有条目。它的速度一直比wc快,后者是一个标准的unix工具,其唯一的目的就是计算行、单词和字符。

票数 0
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69150131

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档