为什么使用 istreambuf 迭代器读取文件会随着重复执行而变得更快?
Why reading a file using istreambuf iterators gets faster with repeated execution?
我正在寻找一种将整个文件读入字符串的方法。在网上找了几个技巧,决定对其中两个进行测试,但是结果很奇怪。
我在 Windows 10 笔记本电脑上使用 Visual Studio Community 2019(版本 16.0.3)。文件 "my_text.txt" 的长度为 2,235,259 个字符,大小为 2.183 MB。
完整代码如下:
#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, '[=10=]');
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;
}
结果如下:
情况一:先调用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()?
由于缓存,执行变得更快。
搜索时,浏览文件需要时间。所以虽然有些东西被缓存了,但区别并没有那么大。通过直接读取,可以缓存文件内容本身。所以再次读取它只是指向缓存内存的指针。
第一次尝试需要多长时间取决于缓存中的内容和操作本身。
我正在寻找一种将整个文件读入字符串的方法。在网上找了几个技巧,决定对其中两个进行测试,但是结果很奇怪。
我在 Windows 10 笔记本电脑上使用 Visual Studio Community 2019(版本 16.0.3)。文件 "my_text.txt" 的长度为 2,235,259 个字符,大小为 2.183 MB。
完整代码如下:
#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, '[=10=]');
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;
}
结果如下:
情况一:先调用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()?
由于缓存,执行变得更快。
搜索时,浏览文件需要时间。所以虽然有些东西被缓存了,但区别并没有那么大。通过直接读取,可以缓存文件内容本身。所以再次读取它只是指向缓存内存的指针。
第一次尝试需要多长时间取决于缓存中的内容和操作本身。