Почему чтение файла с использованием итераторов istreambuf ускоряется при повторном выполнении? - PullRequest
2 голосов
/ 06 мая 2019

Я искал способ прочитать весь файл в строку. Я нашел несколько методов в интернете и решил проверить две из них, но результаты были странными.

Я использую Visual Studio Community 2019 (версия 16.0.3) на ноутбуке с Windows 10. Длина файла "my_text.txt" составляет 2 235 259 символов, а его размер - 2,183 МБ.

Вот полный код:

#include <chrono>
#include <fstream>
#include <iostream>
#include <string>

// first technique
void read_string_1(std::ifstream& fstr, std::string& result)
{
    fstr.seekg(0, std::ios::end);
    size_t length = fstr.tellg();
    fstr.seekg(0);
    result = std::string(length + 1, '\0');
    fstr.read(&result[0], length);
}

// second technique
void read_string_2(std::ifstream& fstr, std::string& result)
{
    result = std::string( (std::istreambuf_iterator<char>(fstr)), (std::istreambuf_iterator<char>()) );
}

int main()
{
    std::ifstream ifile{ "my_text.txt", std::ios_base::binary };
    if (!ifile)
        throw std::runtime_error("Error!");

    std::string content;

    for (int i = 0; i < 10; ++i)
    {
        std::chrono::high_resolution_clock::time_point p1 = std::chrono::high_resolution_clock::now();
        read_string_1(ifile, content);
        std::chrono::high_resolution_clock::time_point p2 = std::chrono::high_resolution_clock::now();
        auto duration1 = std::chrono::duration_cast<std::chrono::microseconds>(p2 - p1).count();
        std::cout << "M1:" << duration1 << std::endl;
    }

    for (int i = 0; i < 10; ++i)
    {
        std::chrono::high_resolution_clock::time_point p3 = std::chrono::high_resolution_clock::now();
        read_string_2(ifile, content);
        std::chrono::high_resolution_clock::time_point p4 = std::chrono::high_resolution_clock::now();
        auto duration2 = std::chrono::duration_cast<std::chrono::microseconds>(p4 - p3).count();
        std::cout << "M2:" << duration2 << std::endl;
    }

    return 0;
}

А вот и результаты:

Случай 1: сначала вызвать read_string_1 (), затем вызвать read_string_2 ().

M1:7389
M1:8821
M1:6303
M1:6725
M1:5951
M1:8097
M1:5651
M1:6156
M1:6110
M1:5848
M2:827
M2:15
M2:15
M2:15
M2:14
M2:13
M2:14
M2:13
M2:14
M2:14

Случай 2: сначала вызвать read_string_2 (), а затем read_string_1 ().

M1:940311
M1:352
M1:16
M1:13
M1:15
M1:15
M1:13
M1:13
M1:14
M1:14
M2:4668
M2:4761
M2:4881
M2:7446
M2:5050
M2:5572
M2:5255
M2:5108
M2:5234
M2:5072

Конечно, результаты отличаются каждый раз, но они следуют общей схеме. Как видите, read_string_1 () довольно непротиворечива, но время выполнения read_string_2 () озадачивает. Почему в обоих случаях это происходит быстрее при повторном выполнении? Почему в случае 2 выполнение первого запуска занимает так много времени? Что происходит на заднем плане? Я делаю что-то неправильно? И в конце концов, какая функция быстрее, read_string_1 () или read_string_2 ()?

1 Ответ

3 голосов
/ 06 мая 2019

Выполнение становится быстрее из-за кэширования.

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

Сколько времени занимает первая попытка, зависит от того, что находится в кэше, и от самой операции.

...