Linux/perl mmap性能

Linux/perl mmap性能,linux,perl,random,mmap,Linux,Perl,Random,Mmap,我正在尝试使用mmap优化对大型数据集的处理。数据集在千兆字节范围内。其想法是将整个文件映射到内存中,允许多个进程同时处理数据集(只读)。但它并没有像预期的那样工作 作为一个简单的测试,我只需mmap文件(使用perl的Sys::mmap模块,使用“mmap”sub,我相信它直接映射到底层的C函数)并让进程休眠。执行此操作时,代码在从mmap调用返回之前花费了一分钟多的时间,尽管此测试没有对mmap文件执行任何操作,甚至没有读取 猜测一下,我想linux可能要求在第一次mmap'ed时读取整个文

我正在尝试使用mmap优化对大型数据集的处理。数据集在千兆字节范围内。其想法是将整个文件映射到内存中,允许多个进程同时处理数据集(只读)。但它并没有像预期的那样工作

作为一个简单的测试,我只需mmap文件(使用perl的Sys::mmap模块,使用“mmap”sub,我相信它直接映射到底层的C函数)并让进程休眠。执行此操作时,代码在从mmap调用返回之前花费了一分钟多的时间,尽管此测试没有对mmap文件执行任何操作,甚至没有读取

猜测一下,我想linux可能要求在第一次mmap'ed时读取整个文件,所以在第一个进程中映射完文件后(当它处于睡眠状态时),我在另一个进程中调用了一个简单的测试,尝试读取文件的前几兆字节

令人惊讶的是,第二个进程在从mmap调用返回之前似乎也花费了很多时间,大约与第一次mmap文件的时间相同

我已经确保正在使用MAP_SHARED,并且第一次映射文件的进程仍然处于活动状态(它没有终止,mmap也没有取消映射)

我希望一个mmap文件可以让我为多个工作进程提供对大文件的有效随机访问,但是如果每个mmap调用都需要先读取整个文件,那么就有点困难了。我还没有使用长时间运行的进程来测试第一次延迟后的访问是否快速,但我希望使用MAP_SHARED和另一个单独的进程就足够了

我的理论是,mmap将或多或少立即返回,linux将或多或少按需加载块,但我看到的行为正好相反,这表明每次调用mmap时都需要读取整个文件


你知道我做错了什么,或者我完全误解了mmap的工作原理吗?

听起来确实令人惊讶。为什么不试试纯C版本呢


或者在不同的OS/perl版本上尝试您的代码。

如果您有相对较新的perl版本,则不应使用Sys::Mmap。你应该使用PerlIO的图层


你能发布你正在使用的代码吗?

好的,找到问题了。正如人们所怀疑的那样,linux和perl都不是罪魁祸首。要打开并访问该文件,请执行以下操作:

#!/usr/bin/perl
# Create 1 GB file if you do not have one:
# dd if=/dev/urandom of=test.bin bs=1048576 count=1000
use strict; use warnings;
use Sys::Mmap;

open (my $fh, "<test.bin")
    || die "open: $!";

my $t = time;
print STDERR "mmapping.. ";
mmap (my $mh, 0, PROT_READ, MAP_SHARED, $fh)
    || die "mmap: $!";
my $str = unpack ("A1024", substr ($mh, 0, 1024));
print STDERR " ", time-$t, " seconds\nsleeping..";

sleep (60*60);
#/usr/bin/perl
#如果没有1 GB文件,请创建1 GB文件:
#dd if=/dev/uradom of=test.bin bs=1048576计数=1000
严格使用;使用警告;
使用Sys::Mmap;

open(my$fh,“在32位系统上,
mmap()
s的地址空间相当有限(并且因操作系统而异)。请注意,如果您使用的是多GB文件,并且您仅在64位系统上进行测试。(我更愿意在注释中写下这一点,但我还没有足够的信誉点)

有关mmap的perl性能,请参阅。但是有一个很大的陷阱。如果您的数据集位于经典HD上,并且您将从多个进程读取数据,则很容易陷入随机访问,并且IO将下降到不可接受的值(20~40次)。

有一件事可以提高性能,那就是使用“madvise(2)””“也许最容易
通过内联::C完成。“madvise”让您告诉内核您的访问模式将是什么样的(例如,顺序、随机等)。

好的,这里有另一个更新。使用Sys::Mmap或PerlIO的“:Mmap”属性在perl中都可以正常工作,但最多只有2 GB的文件(神奇的32位限制)。一旦文件超过2 GB,就会出现以下问题:

使用Sys::Mmap和substr访问文件时,substr似乎只接受位置参数的32位int,即使在perl支持64位的系统上也是如此。至少发布了一个错误:


使用
open(my$fh)如果我可以插入我自己的模块:我建议使用,而不是。它比Sys::Mmap更易于使用,也不容易崩溃。

您对该文件的访问最好是随机的,以证明完整的Mmap是正确的。如果您的使用分布不均匀,您可能最好使用seek,读取新的malloced区域,然后处理免费的rins然后重复。然后用4k的倍数块工作,比如说64k左右


我曾经测试过很多字符串模式匹配算法。对整个文件进行mmaping是缓慢而毫无意义的。读取一个32kish的静态缓冲区更好,但仍然不是特别好。读取一个新的malloced块,处理它,然后放手让内核在幕后创造奇迹。速度上的差异是巨大的,但是模式匹配是非常快速复杂的,必须比通常需要更多地强调处理效率。

我已经研究了perl OS接口,它或多或少直接调用C版本,但除非我弄清楚,否则我可能还会测试C版本。至于OS/perl版本,我已经测试了两个一个是Ubuntu 8.04.2(linux 2.6.24-22,perl 5.8.8),另一个是Ubuntu 9.04(linux 2.6.28-13,perl 5.10.0)。相同的行为。第二个系统是笔记本电脑,我可以肯定地确认,当从我的测试中调用mmap时,涉及到严重的磁盘io。同意,PerlIO mmap层可能更可取,因为它还允许通过简单地添加/删除mmap属性来运行带/不带mmap的相同代码。无论如何,我发现了问题m、 发布了代码,问题解决了。将问题解决到2GB。对于更大的文件,perl仍然存在问题,请参阅我的其他相关答案。PerlIO的mmap层可以访问/dev/mem读/写块吗?@donaldh我不知道,如果你给我发了一些代码(C或其他格式)这样,我可以尝试在Perl中复制它。+1。看起来是一个有效的答案,可以解决我提出的问题,所以感谢您没有将其作为注释发布。正如我在其他答案中发布的一样,即使是在64位上