簡體   English   中英

Linux / perl mmap性能

[英]Linux/perl mmap performance

我正在嘗試使用mmap優化大型數據集的處理。 數據集在千兆字節范圍內。 我們的想法是將整個文件映射到內存中,允許多個進程同時處理數據集(只讀)。 但它沒有按預期工作。

作為一個簡單的測試,我簡單地mmap文件(使用perl的Sys :: Mmap模塊,使用“mmap”子,我相信它直接映射到底層的C函數)並讓進程休眠。 執行此操作時,代碼在從mmap調用返回之前花費的時間超過一分鍾,盡管此測試無效 - 甚至不讀取 - 來自mmap的文件。

猜測,我雖然linux可能需要在第一個mmap時讀取整個文件,所以在第一個進程中映射文件之后(當它正在休眠時),我在另一個嘗試讀取的過程中調用了一個簡單的測試文件的前幾兆字節。

令人驚訝的是,似乎第二個進程在從mmap調用返回之前也花費了大量時間,與mmap第一次執行文件的時間大致相同。

我已確保正在使用MAP_SHARED,並且第一次映射文件的進程仍處於活動狀態(它尚未終止,並且mmap尚未取消映射)。

我期望一個mmapped文件允許我給多個工作進程有效隨機訪問大文件,但是如果每個mmap調用都需要先讀取整個文件,那就更難了。 我沒有測試使用長時間運行的進程來查看第一次延遲后訪問是否很快,但我希望使用MAP_SHARED,另一個單獨的進程就足夠了。

我的理論是mmap會或多或少地立即返回,並且linux會根據需要或多或少地加載塊,但我看到的行為恰恰相反,表明它需要在每次調用mmap時讀取整個文件。

知道我做錯了什么,或者我是否完全誤解了mmap應該如何工作?

好的,發現了問題。 正如所懷疑的那樣,無論是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);

如果您測試該代碼,就沒有像我在原始代碼中找到的那樣的延遲,並且在創建最小樣本之后(總是這樣做,對!)原因突然變得明顯。

錯誤是我在我的代碼中將$mh標量視為句柄,這是一種重量輕且可以輕松移動的內容(讀取:按值傳遞)。 事實證明,它實際上是一個GB長字符串,絕對不是你想要移動的東西而不創建一個顯式引用(perl語言表為“指針”/句柄值)。 因此,如果您需要以散列或類似方式存儲,請確保存儲\\$mh ,並在需要使用它時將其解析為${$hash->{mh}} ,通常作為substr中的第一個參數或類似的。

如果你有一個相對較新的Perl版本,你不應該使用Sys :: Mmap。 你應該使用PerlIO的mmap層。

你可以發布你正在使用的代碼嗎?

在32位系統上, mmap()的地址空間相當有限(並且因OS而異)。 請注意,如果您使用的是千兆字節文件而您只是在64位系統上進行測試。 (我本來希望在評論中寫這個,但我還沒有足夠的聲譽點)

可以幫助表現的一件事是使用'madvise(2)'。 可能最容易通過Inline :: C完成。 'madvise'讓你告訴內核你的訪問模式是什么樣的(例如順序,隨機等)。

這聽起來確實令人驚訝。 為什么不試試純C版?

或者在不同的OS / perl版本上嘗試您的代碼。

有關使用mmap的perl性能,請參閱Wide Finder 但是有一個很大的缺陷。 如果您的數據集將使用經典高清,並且您將從多個進程中讀取數據,則您可以輕松地進入隨機訪問狀態,並且您的IO​​將降至不可接受的值(20~40次)。

好的,這是另一個更新。 使用Sys :: Mmap或PerlIO的“:mmap”屬性在perl中都可正常工作,但最多只能處理2 GB文件(神奇的32位限制)。 一旦文件超過2 GB,就會出現以下問題:

使用Sys :: Mmap和substr訪問文件,似乎substr只接受位置參數的32位int,即使在perl支持64位的系統上也是如此。 至少發布了一個關於它的錯誤:

#62646:帶substr的最大字符串長度

使用open(my $fh, "<:mmap", "bigfile.bin") ,一旦文件大於2 GB,似乎perl將掛起/或堅持在第一次讀取時讀取整個文件(不確定)其中,我從未跑過足夠長的時間來看它是否已經完成),導致表現遲鈍。

我沒有找到任何解決方法,我目前仍然堅持使用慢文件(非mmap'ed)操作來處理這些文件。 除非我找到一個解決方法,否則我可能不得不用C或其他更高級語言來實現處理,這種語言更好地支持mmap的大文件。

如果我可以插入我自己的模塊:我建議使用File :: Map而不是Sys :: Mmap 它比Sys :: Mmap更容易使用,並且不易崩潰。

您對該文件的訪問最好是隨機的,以證明完整的mmap。 如果您的使用不均勻分布,那么您可能會更好地尋找,閱讀新鮮的malloced區域並處理,免費,沖洗和重復。 並使用4k倍數的塊,比如64k左右。

我曾經對很多字符串模式匹配算法進行基准測試。 mmaping整個文件是緩慢和毫無意義的。 讀取靜態32kish緩沖區更好,但仍然不是特別好。 閱讀新鮮的malloced塊,處理它然后讓它繼續允許內核在引擎蓋下工作奇跡。 速度的差異是巨大的 ,但是再次模式匹配的復雜性非常快,並且必須更加強調處理效率,而不是通常需要的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM