【发布时间】:2021-08-29 11:41:50
【问题描述】:
我必须从一个大文件(超过 7GB)中逐行读取一些数据,它包含一个顶点坐标列表和面到顶点连接信息以形成一个网格。我还在学习如何在 Linux 上使用 open、mmap 和在 Windows 上使用 CreateFileA、CreateFileMapping、MapViewOfFile。 Linux 和 Windows 版本都是 64 位编译的。
当我使用g++-10 test.cpp -O3 -std=c++17 在 Linux(使用 docker)上时,我大约需要 6 秒。
当我在 Windows(我的实际 PC)上使用(版本 19.29.30037 x64)cl test.cpp /EHsc /O3 /std:c++17 时,我得到 13 秒,而使用 clang++-11(来自 Visual Studio 构建工具)我得到 11 秒。
两个系统(同一台 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 信息运行。
感谢您抽出宝贵时间阅读。非常感谢任何提示,如果有任何不清楚的地方,我们深表歉意。
【问题讨论】:
-
你的“问题”中没有问题。
-
你说得对,我忘记了'?',现在更正了。
-
在语句中添加问号不会产生问题。如果您想知道您的代码是否有问题,那么接受一个归结为 “使用我在互联网上找到的另一个随机库,让我们假装 POSIX 并非无用”的答案 是错误的动作。请拨打tour 了解这个地方的运作方式。
-
感谢您花时间看这个,我不接受这个答案,因为它只是一个建议,问题正是你所说的。我想知道我是否对 windows 中的参数做错了什么来模仿 mmap 的行为。
标签: c++ linux windows c++17 file-mapping