我必须从一个大文件(超过 7GB)中逐行读取一些数据,它包含顶点坐标列表和面到顶点连接信息以形成网格。我也在学习如何在 Linux 和Windows上使用open
, 。Linux 和 Windows 版本都是 64 位编译的。mmap
CreateFileA
CreateFileMapping
MapViewOfFile
当我在 Linux(使用 docker)上时,g++-10 test.cpp -O3 -std=c++17
我得到了大约 6 秒。当我在 Windows(我的实际 PC)上使用(版本 19.29.30037 x64)cl test.cpp /EHsc /O3 /std:c++17
时,我得到 13s,使用clang++-11
(来自 Visual Studio Build Tools)我得到 11s。
两个系统(同一台 PC,但一个使用 docker)使用相同的确切代码,除了生成const char*
表示内存阵列和表示uint64_t
内存大小的大小。
这是我切换平台的方式:
// includes for using a specific platform API
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
// using windows handle void*
#define handle_type HANDLE
#else
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
// using file descriptors
#define handle_type int
#endif
具体来说,在 char-s 数组中获取内存的代码是:
using uint_t = std::size_t;
// open the file -----------------------------------------------------------------------------
handle_type open(const std::string& filename) {
#ifdef _WIN32
// see windows file mapping api for parameter explanation
return ::CreateFileA(filename.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); // private access
#else
return ::open(filename.c_str(), O_RDONLY);
#endif
}
// get the memory size to later have a bound for reading -------------------------------------
uint_t memory_size(handle_type fid) {
#ifdef _WIN32
LARGE_INTEGER size{};
if (!::GetFileSizeEx(fid, &size)) {
std::cerr << "file not found\n";
return size.QuadPart;
}
return size.QuadPart;
#else
struct stat sb;
// get the file stats and check if not zero size
if (fstat(fid, &sb)) {
std::cerr << "file not found\n";
return decltype(sb.st_size){};
}
return sb.st_size;
#endif
}
// get the actual char array to access memory ------------------------------------------------
const char* memory_map(handle_type fid, uint_t memory_size) {
#ifdef _WIN32
HANDLE mapper = ::CreateFileMapping(fid, NULL, PAGE_READONLY, 0, 0, NULL);
return reinterpret_cast<const char*>(::MapViewOfFile(mapper, FILE_MAP_READ, 0, 0, memory_size));
#else
return reinterpret_cast<const char*>(::mmap(NULL, memory_size, PROT_READ, MAP_PRIVATE, fid, 0));
#endif
}
我对这种解析完全陌生,想知道我在选择 Windows API 中的参数时是否做错了(模仿 mmap 的行为),或者时间差异是否与编译器/系统有关,必须接受?
在 Linux 和 Windows 上,打开、获取内存大小和内存映射的实际时间可以忽略不计,其余代码是相同的,因为它只使用const char*
和size_t
信息进行操作。
感谢您花时间阅读。非常感谢任何提示,如果有任何不清楚的地方,我们深表歉意。