سؤال

أحاول تحسين التعامل مع مجموعات البيانات الكبيرة باستخدام mmap.توجد مجموعة البيانات في نطاق الجيجابايت.كانت الفكرة هي دمج الملف بأكمله في الذاكرة، مما يسمح لعمليات متعددة بالعمل على مجموعة البيانات بشكل متزامن (للقراءة فقط).على الرغم من ذلك، فإنه لا يعمل كما هو متوقع.

كاختبار بسيط، أقوم ببساطة بتعيين mmap للملف (باستخدام وحدة Sys::Mmap الخاصة بـ Perl، باستخدام الوحدة الفرعية "mmap" التي أعتقد أنها تقوم بتعيينها مباشرة إلى وظيفة C الأساسية) وجعل العملية في وضع السكون.عند القيام بذلك، يقضي الكود أكثر من دقيقة قبل أن يعود من استدعاء mmap، على الرغم من أن هذا الاختبار لا يفعل شيئًا - ولا حتى قراءة - من الملف mmap'ed.

أعتقد، على الرغم من أنني ربما تطلب Linux قراءة الملف بأكمله عند تعيينه لأول مرة، لذا بعد تعيين الملف في العملية الأولى (أثناء وجوده في وضع السكون)، قمت باستدعاء اختبار بسيط في عملية أخرى حاولت قراءة الميجابايت القليلة الأولى من الملف.

من المثير للدهشة، أنه يبدو أن العملية الثانية تستغرق أيضًا الكثير من الوقت قبل العودة من استدعاء mmap، تقريبًا في نفس الوقت الذي تستغرقه عملية رسم خريطة للملف في المرة الأولى.

لقد تأكدت من استخدام MAP_SHARED وأن العملية التي عيّنت الملف في المرة الأولى لا تزال نشطة (وأنها لم يتم إنهاؤها، وأن mmap لم يتم إلغاء تعيينها).

كنت أتوقع أن يسمح لي ملف mmapped بمنح عمليات عاملة متعددة وصولاً عشوائيًا فعالاً إلى الملف الكبير، ولكن إذا كانت كل مكالمة mmap تتطلب قراءة الملف بالكامل أولاً، فسيكون الأمر أصعب قليلاً.لم أختبر استخدام العمليات طويلة الأمد لمعرفة ما إذا كان الوصول سريعًا بعد التأخير الأول، لكنني توقعت أن استخدام MAP_SHARED وأن عملية منفصلة أخرى ستكون كافية.

كانت نظريتي هي أن mmap سيعود بشكل أو بآخر على الفور، وأن Linux سيقوم بتحميل الكتل بشكل أو بآخر عند الطلب، ولكن السلوك الذي أراه هو عكس ذلك، مما يشير إلى أنه يتطلب قراءة الملف بأكمله في كل استدعاء لـ mmap.

هل لديك أي فكرة عما أفعله بشكل خاطئ، أو إذا كنت قد أسأت فهم كيفية عمل mmap؟

هل كانت مفيدة؟

المحلول

وطيب، وجدت هذه المشكلة. كما المشتبه بهم، لم يكونوا لينكس أو بيرل المسؤولة عن ذلك. لفتح والوصول إلى الملف أفعل شيئا من هذا القبيل:

#!/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 طويلة، نهائيا لا شيء كنت تريد التحرك دون خلق إشارة صريحة (مشتركة بيرل ل"مؤشر" قيمة / مقبض). حتى إذا كنت تحتاج إلى تخزين في في تجزئة أو ما شابه ذلك، تأكد من تخزين \$mh، وderef عندما كنت في حاجة لاستخدامها مثل ${$hash->{mh}}، وعادة كمعلمة الأول في SUBSTR أو ما شابه ذلك.

نصائح أخرى

إذا كان لديك إصدار حديث نسبيا من بيرل، يجب أن لا تستخدم تميز الكلية :: Mmap. يجب أن تستخدم mmap طبقة PerlIO ل.

هل قمت بنشر الرمز الذي تستخدمه؟

في أنظمة 32 بت مساحة العنوان لmmap()s بل هي محدودة (ويختلف من نظام التشغيل إلى OS). يكون على بينة من أنه إذا كنت تستخدم ملفات متعددة غيغا بايت والخاص يتم اختبار فقط على نظام 64 بت. (كنت أفضل أن أكتب هذا في تعليق ولكن ليس لدي نقاط سمعة كافية حتى الآن)

والشيء الوحيد الذي يمكن أن تساعد في الأداء هو استخدام "madvise (2). ربما أكثر سهولة يتم عن طريق مضمنة :: C. "madvise" يتيح لك معرفة نواة ما نمط الوصول الخاصة بك وسوف يكون مثل (على سبيل المثال متتابعة، عشوائية، الخ).

وهذا لا يبدو مفاجئا. لماذا لا نحاول نسخة C النقي؟

وأو محاولة الشفرة على نظام تشغيل مختلف / نسخة بيرل.

الباحث على نطاق واسع للحصول على بيرل الأداء مع mmap. ولكن هناك واحد شرك كبير. إذا مجموعة البيانات الخاصة بك وسوف يكون على HD الكلاسيكية وسوف تقرأ من عمليات متعددة، هل يمكن أن تقع بسهولة في الوصول العشوائي، وسوف IO الخاص تسقط على قيم غير مقبولة (20 ~ 40 مرات).

حسنًا، إليك تحديثًا آخر.يعمل استخدام Sys::Mmap أو سمة ":mmap" الخاصة بـ PerlIO بشكل جيد في Perl، ولكن يصل حجم الملفات إلى 2 جيجابايت فقط (الحد السحري 32 بت).وبمجرد أن يزيد حجم الملف عن 2 جيجا بايت تظهر المشاكل التالية:

باستخدام Sys::Mmap وsubstr للوصول إلى الملف، يبدو أن substr يقبل فقط int 32 بت لمعلمة الموضع، حتى على الأنظمة التي يدعم فيها Perl 64 بت.هناك خطأ واحد على الأقل تم نشره حول هذا الموضوع:

#62646:الحد الأقصى لطول السلسلة مع substr

استخدام open(my $fh, "<:mmap", "bigfile.bin"), ، بمجرد أن يصبح الملف أكبر من 2 غيغابايت، يبدو أن لغة Perl إما ستتوقف/أو تصر على قراءة الملف بأكمله في القراءة الأولى (لست متأكدًا من ذلك، لم أقم بتشغيله لفترة كافية لمعرفة ما إذا كان قد اكتمل)، مما يؤدي إلى بطء شديد أداء.

لم أجد أي حل بديل لأي من هذه الملفات، وأنا حاليًا عالق في عمليات الملفات البطيئة (غير المتوافقة مع mmap'ed) للعمل على هذه الملفات.وما لم أجد حلاً بديلاً، فقد أضطر إلى تنفيذ المعالجة بلغة C أو لغة أخرى ذات مستوى أعلى تدعم تعيين الملفات الضخمة بشكل أفضل.

إذا كان بإمكاني توصيل الوحدة الخاصة بي:أنصح باستخدام ملف::خريطة بدلاً من سيس::Mmap.إنه أسهل في الاستخدام وأقل عرضة للتعطل من Sys::Mmap.

وصولك إلى هذا الملف قد يكون أفضل عشوائي جيدا لتبرير mmap الكامل. إذا لم يتم توزيع استخدامك بالتساوي، وكنت أفضل ربما قبالة مع السعي، وقراءة لمنطقة malloced الطازجة وعملية، مجانا، شطف، وتكرار. والعمل مع قطع من مضاعفات 4K، ويقول 64K أو نحو ذلك.

وأنا قياسها مرة واحدة في نمط الكثير سلسلة مطابقة الخوارزميات. mmaping الملف بأكمله كان بطيئا والعبث. القراءة لمنطقة عازلة 32kish ثابت كان أفضل، ولكن لا تزال ليست جيدة بشكل خاص. القراءة لقطعة malloced حديثا، ومعالجة ذلك وبعد ذلك تركه يسمح نواة للعمل عجائب تحت غطاء محرك السيارة. وكان الفرق في السرعة <م> هائلة ، ولكن بعد ذلك مرة أخرى نمط مطابقة هو complexitywise سريع جدا ومزيد من التركيز يجب ان توضع على التعامل مع كفاءة مما هو مطلوب عادة ربما.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top