随机访问 C++ 和 Python 时 Linux 内存映射文件性能不佳

2023-12-30

在尝试使用内存映射文件创建多 GB 文件(大约 13 GB)时,我遇到了 mmap() 的问题。最初的实现是在 Windows 上使用 boost::iostreams::mapped_file_sink 在 c++ 中完成的,一切顺利。然后代码在 Linux 上运行,在 Windows 上花费几分钟的时间在 Linux 上则变成了几个小时。

这两台机器是相同硬件的克隆:Dell R510 2.4GHz 8M 高速缓存 16GB RAM 1TB 磁盘 PERC H200 控制器。

Linux 是 Oracle Enterprise Linux 6.5,使用 3.8 内核和 g++ 4.83。

有人担心 boost 库可能存在问题,因此使用 boost::interprocess::file_mapping 和本机 mmap() 完成了实现。所有三个人都表现出相同的行为。当 Linux 性能严重下降时,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 看起来稍快一些)。对于 C++ 和 Python,Linux 上的性能似乎下降了大约 3Gb(每个 int64 4 亿 * 8 字节 = 3.2Gb)。

我知道在 32 位 Linux 上 3Gb 是一个神奇的边界,但我不知道 64 位 Linux 上有类似的行为。

结果的要点是,在 4 亿个 int64 下,Windows 上的时间为 1.4 分钟,Linux 上的时间为 1.7 小时。我实际上正在尝试映射近 13 亿个 int64。

谁能解释一下为什么 Windows 和 Linux 之间的性能差距如此之大?

任何帮助或建议将不胜感激!

负载测试.cpp http://pastie.org/9645329

Makefile http://pastie.org/9645338

负载测试.vcxproj http://pastie.org/9645344

更新了 mmap_test.py http://pastie.org/9649752

原始mmap_test.py http://pastie.org/9645348

更新结果 http://goo.gl/Xqhngt更新了 Python 代码...Python 速度现在可与 C++ 相媲美

原始结果 http://goo.gl/n8QMff注意:Python 结果已过时


编辑:升级为“正确答案”。问题出在 Linux 处理“脏页”的方式上。我仍然希望我的系统时不时地刷新脏页,所以我不允许它有太多未完成的页面。但与此同时,我可以证明这就是正在发生的事情。

我这样做了(使用“sudo -i”):

# echo 80 > /proc/sys/vm/dirty_ratio
# echo 60 > /proc/sys/vm/dirty_background_ratio

这给出了这些设置 VM 脏设置:

grep ^ /proc/sys/vm/dirty*
/proc/sys/vm/dirty_background_bytes:0
/proc/sys/vm/dirty_background_ratio:60
/proc/sys/vm/dirty_bytes:0
/proc/sys/vm/dirty_expire_centisecs:3000
/proc/sys/vm/dirty_ratio:80
/proc/sys/vm/dirty_writeback_centisecs:500

这使得我的基准测试运行如下:

$ ./a.out m64 200000000
Setup Duration 33.1042 seconds
Linux: mmap64
size=1525 MB
Mapping Duration 30.6785 seconds
Overall Duration 91.7038 seconds

与“之前”比较:

$ ./a.out m64 200000000
Setup Duration 33.7436 seconds
Linux: mmap64
size=1525
Mapping Duration 1467.49 seconds
Overall Duration 1501.89 seconds

其中有这些虚拟机脏设置:

grep ^ /proc/sys/vm/dirty*
/proc/sys/vm/dirty_background_bytes:0
/proc/sys/vm/dirty_background_ratio:10
/proc/sys/vm/dirty_bytes:0
/proc/sys/vm/dirty_expire_centisecs:3000
/proc/sys/vm/dirty_ratio:20
/proc/sys/vm/dirty_writeback_centisecs:500

我不确定应该使用什么设置来获得理想的性能,同时仍然不会将所有脏页永远留在内存中(这意味着如果系统崩溃,则需要更长的时间才能写入磁盘)。

对于历史:这是我最初写的“非答案” - 这里的一些评论仍然适用......

不是真正的答案,但我发现相当有趣的是,如果我将代码更改为首先读取整个数组,然后将其写出,那么它比在同一个循环中执行这两个操作要快得多。我明白,如果您需要处理非常大的数据集(大于内存),那么这是完全没有用的。使用发布的原始代码,100M uint64 值的时间为 134 秒。当我分割读和写周期时,它是 43 秒。

这是DoMapping修改后的功能[仅我更改的代码]:

struct VI
{
    uint32_t value;
    uint32_t index;
};


void DoMapping(uint64_t* dest, size_t rowCount)
{
   inputStream->seekg(0, std::ios::beg);
   std::chrono::system_clock::time_point startTime = std::chrono::system_clock::now();
   uint32_t index, value;
   std::vector<VI> data;
   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)));
       VI d = {index, value};
       data.push_back(d);
   }
   for (size_t i = 0; i<rowCount; ++i)
   {
       value = data[i].value;
       index = data[i].index;
       dest[index] = value;
   }
   std::chrono::duration<double> mappingTime = std::chrono::system_clock::now() - startTime;
   std::cout << "Mapping Duration " << mappingTime.count() << " seconds" << std::endl;
   inputStream.reset();
}

我目前正在运行一个包含 200M 记录的测试,这在我的机器上需要大量时间(在没有代码更改的情况下需要 2000 多秒)。很明显,所花费的时间来自磁盘 I/O,并且我看到 IO 速率为 50-70MB/s,这非常好,因为我并不真正期望我相当简单的设置能够提供太多比那更多的。对于较大的尺寸,改进并不那么好,但仍然是一个不错的改进:总时间为 1502 秒,而“在同一循环中读写”则为 2021 秒。

另外,我想指出,对于任何系统来说,这都是一个相当糟糕的测试 - Linux 明显比 Windows 差的事实不是重点 - 你并不真的想映射一个大文件并写入 8 个字节 [意思是4KB 页必须随机读入] 每个页。如果这反映了您真实的应用程序,那么您应该认真地以某种方式重新考虑您的方法。当您有足够的可用内存以使整个内存映射区域适合 RAM 时,它将运行良好。

我的系统中有足够的 RAM,所以我相信问题是 Linux 不喜欢太多“脏”的映射页面。

我感觉这可能与此有关:https://serverfault.com/questions/126413/limit-linux-background-flush-dirty-pages https://serverfault.com/questions/126413/limit-linux-background-flush-dirty-pages更多解释:http://www.westnet.com/~gsmith/content/linux-pdflush.htm http://www.westnet.com/~gsmith/content/linux-pdflush.htm

不幸的是,我也很累,需要睡觉。明天我会看看是否可以尝试这些 - 但不要屏住呼吸。就像我说的,这并不是一个真正的答案,而是一个不太适合评论的长评论(并且包含代码,在评论中阅读这完全是垃圾)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

随机访问 C++ 和 Python 时 Linux 内存映射文件性能不佳 的相关文章

随机推荐

  • EPPLUS 可清除一系列细胞的内容物

    我想使用 EPPLUS 清除一系列细胞 我尝试了下面的语法 但它给了我一个错误 你调用的对象是空的 使用 EPPLUS 清除细胞 A24 C36 内容物的正确方法是什么 ExcelPackage package new ExcelPacka
  • C# travis 的问题

    特拉维斯 西尔现在支持 C http docs travis ci com user languages csharp 测试版 尝试了 8 种不同的方法后 我找不到解决我的问题的方法 我有一个 ASP MVC 项目 travis 使用 mo
  • 如何使用 LIKE 运算符在 SQL Server 中进行此匹配?

    我正在尝试匹配价格字符串 例如 25 00 来查找相应的货币符号 例如 25 00 应与美元匹配 这已经很有效了 然而 当我输入 25 00 无货币符号 时 我在 CUP 上出现了不需要的匹配 我在 SQL Server 2012 中设置了
  • iOS 8 Today 小部件对齐问题

    这是我的故事板 我正在使用自动布局 而不是使用尺寸类别 When I ran it on iPhone 5s it works fine both portrait and landscape But when I ran it on iP
  • Office.js 使浏览器历史记录功能无效,破坏历史记录使用情况

    Office js 的官方版本可以在这里找到 https appsforoffice microsoft com lib 1 hosted office js 它包含以下代码行 window history replaceState nul
  • 当 Facebook 用户点击 FB Like 按钮时,我如何向他们发送电子邮件?

    用户点击我页面上的 Facebook Like 按钮后 我想自动向他们发送一封电子邮件 这可能吗 您不能强制用户连接您的应用程序并授予email单击 赞 按钮即可获得许可 不过你可以订阅edge create event http deve
  • 对列组应用函数

    我该如何使用apply或者一个相关的函数来创建一个新的数据框 其中包含一个非常大的数据框中每对列的行平均值的结果 我有一个可以输出的仪器n在大量样本上复制测量值 其中每个测量值都是一个向量 所有测量值都是相同长度的向量 我想计算每个样本的所
  • Angular - 如何查看过滤器结果数组以了解控制器的更改

    我有一个过滤器 可以通过 ng repeat 列表根据某些条件进行过滤 我如何查看由过滤服务创建的结果数组以了解控制器内部的更改 完整的问题和描述在这里角度工厂过滤器 无法将数据传递到过滤器 https stackoverflow com
  • 如何最小化最短路径树的总成本

    我有一个具有正边权重的有向无环图 它具有单个源和一组目标 距离源最远的顶点 我找到从源到每个目标的最短路径 其中一些路径重叠 我想要的是一个最短路径树 它可以最小化所有边上的权重总和 例如 考虑其中两个目标 假设所有边的权重相等 如果它们在
  • Bitmap 从 BitmapFactory.decodeFile(filename) 返回 null

    当我调用此函数时 图像视图中没有图像bitmapFactory decodefile filename 显示空 请为此提供帮助 这是我的代码 public Bitmap ShowImage String imageName String u
  • 为什么一些mysql连接在删除+插入后选择mysql数据库的旧数据?

    我的 python wsgi Web 应用程序中的会话出现问题 2 个 wsgi 守护进程中的每个线程都有一个不同的 持久的 mysqldb 连接 有时 在删除旧会话并创建新会话后 某些连接仍然会在选择中获取旧会话 这意味着它们无法验证会话
  • 如何在javascript中监视窗口选择更改事件

    有没有办法监听window selection的change事件 类似于回调 当用户选择不同的内容时调用 如果您使用的是 jQuery 并且您想要处理 ID 为 的特定项目的选择myInput 你可以这样做 myInput select f
  • 如何在 SQLPlus 或 PL/SQL 中制作菜单?

    我正在制作这个程序 它有一个菜单 可以获取用户的输入并根据他 她的选择执行特定的脚本 大致如下 Please make a selection 1 Do script a 2 Do script b 3 Do script c 我看了这个链
  • 从 MongoDB 中删除重复项

    你好 我在 mongodb 中有大约 500 万个文档 复制 每个文档有 43 个字段 如何删除重复的文档 我尝试过 db testkdd ensureIndex duration 1 protocol type 1 service 1 f
  • 如何将 3d numpy 数组转换为 2d

    我有一个像这样的 3d 矩阵 np arange 16 reshape 4 2 2 array 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 并想以网格格式堆叠它们 最终得到 array 0 1 4 5 2 3
  • TLS V 1.1 和 TLS V 1.2 iOS 问题

    有几个问题 如果我的服务器已经运行 TLS1 2 我是否还需要将 NSAppTransportSecurity 功能添加到我的 info plist 中 如果是 为什么 不是所有运行 iOS9 或 gt iOS10 11 版本的苹果设备都可
  • 将列表元素的连续重复项打包到 Prolog 中的子列表中

    我无法返回问题 9 的答案P 99 九十九个 Prolog 问题 http www ic unicamp br meidanis courses mc336 2009s2 prolog problemas 将列表元素的连续重复项打包到子列表
  • Tradingview的自动调整比例功能:排除指标的绘图

    我有一个指标 可以自动压缩 Y 轴上的整个价格图表 所以我必须在大多数情况下让它不可见 即使双击 y 尺度 图表自动调整功能 也可以包含所有可见指标 有没有办法阻止一个或所有指标这样做 哦 我刚刚找到了答案 只需右键单击 y 刻度即可调出带
  • 如何在 Linux 上将光标锁定在窗口内部?

    我正在尝试为 Linux 制作一款游戏 其中涉及大量快速动作和鼠标光标的快速移动 如果用户想在窗口模式下玩 我很想将光标锁定在窗口内部 以避免在激烈的战斗中意外更改程序 显然 如果用户更改程序或按退出键 这会自行取消 暂停菜单 在 Wind
  • 随机访问 C++ 和 Python 时 Linux 内存映射文件性能不佳

    在尝试使用内存映射文件创建多 GB 文件 大约 13 GB 时 我遇到了 mmap 的问题 最初的实现是在 Windows 上使用 boost iostreams mapped file sink 在 c 中完成的 一切顺利 然后代码在 L