我必须从一个大文件(超过7 7GB)逐行读取一些数据,它包含一个顶点坐标列表和面到顶点的连通性信息,以形成网格。我还在学习如何在Linux上使用open,mmap,在Windows上使用CreateFileA,CreateFileMapping,MapViewOfFile。Linux和Windows版本都是64位编译的。
当我在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。
除了生成表示内存阵列的const char*和表示内存大小的uint64_t大小之外,两个系统(相同的PC,但其中一个使用docker)使用完全相同的代码。
这是我切换平台的方式:
// 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信息进行操作。
感谢您抽出时间来阅读。任何提示都非常感谢,如果有任何不清楚的地方,我们深表歉意。
发布于 2021-06-13 19:30:36
也许你应该看看https://github.com/alitrack/mman-win32,它是一个用于Windows的mmap实现。这样你就不需要为Windows编写不同的代码了。
https://stackoverflow.com/questions/67955471
复制相似问题