尝试使用内存映射文件创建一个多GB(约13GB)文件时,我遇到了mmap()的问题。最初在Windows上使用boost::iostreams::mapped_file_sink进行了实现,并且一切顺利。然后在Linux上运行代码,Windows上花费几分钟的时间在Linux上变成了数小时。这两台机器是相同硬件的克隆:Dell R510 2.4GHz 8M Cache 16GB Ram 1TB Disk PERC H200 Controller。担心可能存在boost库的问题,因此使用boost::interprocess::file_mapping和本机mmap()进行了实现。三者均表现出相同的行为。当Linux性能急剧下降时,Windows和Linux性能在某个点上保持一致。完整源代码和性能数字如下链接。
对于C++测试,Windows和Linux在大约3亿个int64(Linux看起来稍微快一些)时具有类似的性能。看起来,在Linux上,无论是C ++还是Python,在大约3GB(400 million * 8 bytes per int64 = 3.2GB)左右的位置性能下降。我知道在32位Linux上,3GB是一个魔法边界,但不知道64位Linux是否存在类似的行为。结果的要点是:在400 million int64s时,Windows需要1.4分钟,而Linux需要1.7小时。我实际上正在尝试映射近13亿个int64。有人能解释一下Windows和Linux之间性能差异如此之大的原因吗?任何帮助或建议都将不胜感激!
// C++ code using boost::iostreams
void IostreamsMapping(size_t rowCount)
{
std::string outputFileName = "IoStreamsMapping.out";
boost::iostreams::mapped_file_params params(outputFileName);
params.new_file_size = static_cast<boost::iostreams::stream_offset>(sizeof(uint64_t) * rowCount);
boost::iostreams::mapped_file_sink fileSink(params); // NOTE: using this form of the constructor will take care of creating and sizing the file.
uint64_t* dest = reinterpret_cast<uint64_t*>(fileSink.data());
DoMapping(dest, rowCount);
}
void DoMapping(uint64_t* dest, size_t rowCount)
{
inputStream->seekg(0, std::ios::beg);
uint32_t index, value;
for (size_t i = 0; i<rowCount; ++i)
{
inputStream->read(reinterpret_cast<char*>(&index), static_cast<std::streamsize>(sizeof(uint32_t)));
inputStream->read(reinterpret_cast<char*>(&value), static_cast<std::streamsize>(sizeof(uint32_t)));
dest[index] = value;
}
}
为了在另一种语言中重现这个问题,进行了一次最后的Python测试。掉落的位置与原问题相同,因此看起来是同样的问题。
# Python code using numpy
import numpy as np
fpr = np.memmap(inputFile, dtype='uint32', mode='r', shape=(count*2))
out = np.memmap(outputFile, dtype='uint64', mode='w+', shape=(count))
print("writing output")
out[fpr[::2]]=fpr[::2]
对于C++测试,Windows和Linux在大约3亿个int64(Linux看起来稍微快一些)时具有类似的性能。看起来,在Linux上,无论是C ++还是Python,在大约3GB(400 million * 8 bytes per int64 = 3.2GB)左右的位置性能下降。我知道在32位Linux上,3GB是一个魔法边界,但不知道64位Linux是否存在类似的行为。结果的要点是:在400 million int64s时,Windows需要1.4分钟,而Linux需要1.7小时。我实际上正在尝试映射近13亿个int64。有人能解释一下Windows和Linux之间性能差异如此之大的原因吗?任何帮助或建议都将不胜感激!
更新结果:使用更新的 Python 代码后,Python 的速度现在与 C++ 相当。
原始结果 注意:Python 的结果已经过时。
uint32
的整数占用4个字节。每次使用标量索引访问数组时,都会创建一个新的Python整数(无限精度,超过4个字节)(装箱/拆箱很昂贵,这就是为什么应该使用向量操作的原因:out[fpr[::2]]=fpr[::2]
)。 - jfs