Производительность создания C ++ std :: string из входного итератора - PullRequest
8 голосов
/ 08 февраля 2009

Я делаю что-то действительно простое: выкладывая весь текстовый файл с диска в std::string. Мой текущий код в основном делает это:

std::ifstream f(filename);
return std::string(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>());

Маловероятно, что это когда-либо повлияет на производительность программы, но мне все еще было любопытно, медленный ли это способ.

Есть ли риск, что при построении строки будет много перераспределений? Было бы лучше (то есть быстрее) использовать seekg() / tellg() для вычисления размера файла и reserve() столько места в строке перед чтением?

Ответы [ 3 ]

28 голосов
/ 08 февраля 2009

Я протестировал вашу реализацию (1), мою (2) и две другие (3 и 4), которые я нашел в stackoverflow.

Результаты (Среднее из 100 запусков; при использовании gettimeofday, файл содержал 40 абзацев lorem ipsum):

  • readFile1: 764
  • readFile2: 104
  • readFile3: 129
  • readFile4: 402

Реализации:

string readFile1(const string &fileName)
{
    ifstream f(fileName.c_str());
    return string(std::istreambuf_iterator<char>(f),
            std::istreambuf_iterator<char>());
}

string readFile2(const string &fileName)
{
    ifstream ifs(fileName.c_str(), ios::in | ios::binary | ios::ate);

    ifstream::pos_type fileSize = ifs.tellg();
    ifs.seekg(0, ios::beg);

    vector<char> bytes(fileSize);
    ifs.read(&bytes[0], fileSize);

    return string(&bytes[0], fileSize);
}

string readFile3(const string &fileName)
{
    string data;
    ifstream in(fileName.c_str());
    getline(in, data, string::traits_type::to_char_type(
                      string::traits_type::eof()));
    return data;
}

string readFile4(const std::string& filename)
{
    ifstream file(filename.c_str(), ios::in | ios::binary | ios::ate);

    string data;
    data.reserve(file.tellg());
    file.seekg(0, ios::beg);
    data.append(istreambuf_iterator<char>(file.rdbuf()),
                istreambuf_iterator<char>());
    return data;
}
2 голосов
/ 08 февраля 2009

Что произойдет с перформансом, если вы попробуете это сделать? Вместо того, чтобы спрашивать "какой путь быстрее?" Вы можете подумать «эй, я могу измерить это».

Установите цикл, который читает файл заданного размера 10000 раз или около того, и рассчитайте время. Затем сделайте это с помощью метода reserve() и время. Попробуйте это с несколькими разными размерами файлов (от маленьких до огромных) и посмотрите, что вы получите.

0 голосов
/ 08 февраля 2009

Если честно, я не уверен, но то, что я прочитал, действительно зависит от итераторов. В случае итераторов из файловых потоков у него, вероятно, нет встроенного метода для измерения длины файла между начальным и конечным интегратором.

Если это правильно, он будет работать примерно так же, как удваивает свой внутренний объем памяти каждый раз, когда ему не хватает места. В этом случае для n символов в файле будут выделяться Log [n, 2] памяти и удаляться память, а также n * Log [n, 2] копий отдельных символов поверх простого копирования символов в строку.

Как отметил Грег, вы можете также проверить это. Как он сказал, попробуйте разные размеры файлов для обоих методов. Кроме того, вы можете использовать следующее, чтобы получить некоторые количественные показатели.

#include<time.h>
#include<iostream>

...

clock_t time1=0, time2=0, delta;
float seconds;

time1=clock();

//Put code to be timed here

time2=clock();

delta= time2-time1;

seconds =(((float)delta)/((float)CLOCKS_PER_SEC));

std::cout<<"The operation took: "<<seconds<<" seconds."<<std::endl;

...

это должно сработать для определения времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...