هذا هو الأمر perl_performance الذي يمكن تشغيله في موفر الاستضافة المجاني OnWorks باستخدام إحدى محطات العمل المجانية المتعددة عبر الإنترنت مثل Ubuntu Online أو Fedora Online أو محاكي Windows عبر الإنترنت أو محاكي MAC OS عبر الإنترنت
برنامج:
اسم
makepp_perl_performance - كيفية جعل لغة Perl أسرع
الوصف
عادةً ما تأتي أكبر مكاسب الضبط من التحسينات الخوارزمية. ولكن في حين أن هذه
قد يكون من الصعب العثور عليه، وهناك أيضًا الكثير الذي يمكنك القيام به ميكانيكيًا.
Makepp هو برنامج كبير للخدمة الشاقة، حيث السرعة أمر لا بد منه. لقد تم بذل الكثير من الجهد
في تحسينه. وهذا يوثق بعض الأشياء العامة التي وجدناها. حاليا
لقد تم تجاهل الاختبارات الملموسة التي تؤدي إلى هذه النتائج في الغالب، لكنني أخطط لذلك
إضافتها تدريجيا.
إذا كنت تبحث عن كيفية تسريع عملية makepp (بخلاف برمجة Perl التي تضعها في ملف
makefiles)، انظر إلى makepp_speedup. هذه الصفحة مستقلة تمامًا عن makepp، فقط
تهدف إلى جعل نتائجنا متاحة لمجتمع بيرل. بعض هذه التدابير
المنطق السليم، ولكن في بعض الأحيان ننسى لهم. يحتاج الآخرون إلى قياس ليصدقوهم، لذلك:
يقيس، لا تخمين
ملف تعريف البرنامج الخاص بك
يأتي Makepp مع وحدة نمطية ملف التعريف.pm في مستودع السيرة الذاتية الخاص به. يتم تشغيل هذا لأول مرة باعتباره
البرنامج على نسخة (!) من التعليمات البرمجية الخاصة بك، والتي يقوم بأدواتها. ثم تقوم بتشغيل نسختك و
احصل على إحصائيات قابلة للتكوين لكل فاصل زمني وإجمالي نهائي في أغلب الأحيان
تسمى الوظائف وعلى معظم الوقت الذي يقضيه في الوظائف (مطروحًا منه المكالمات الفرعية). كلاهما
يتم تقديمه بشكل مطلق وفي أزواج المتصل والمستدعي. (التوثيق داخل.)
يخبرك هذا بالوظائف الأكثر ترشيحًا للضبط. إنه أيضًا
يمنحك تلميحًا حيث قد تكون الخوارزمية الخاصة بك خاطئة، إما بشكل مفاجئ
وظائف باهظة الثمن، أو من خلال مكالمات متكررة بشكل مدهش.
حدد وقت الحل الخاص بك
أي منهما
بيرل -Mstrict -MBenchmark -we 'my ; هذا الوقت -10، الفرعي { }'
الوقت بيرل -Mstrict -نحن بلدي ؛ ل(0..999_999) { }'
عند تشغيله على أشكال مختلفة من التعليمات البرمجية التي يمكنك التفكير فيها، يمكن أن يعطي نتائج مذهلة.
حتى التعديلات الصغيرة يمكن أن تهم كثيرًا. احرص على عدم "قياس" التعليمات البرمجية التي يمكنها ذلك
احصل على التحسين بعيدًا، لأنك تتجاهل النتيجة، أو لأنها تعتمد على ذلك
الثوابت.
اعتمادًا على نظامك، سيخبرك هذا بالكيلوبايت عن مدى زيادة الدهون في لغة Perl:
بيرل -Mstrict -we ' ; النظام "ps -ovsz $$"'
أدناه نعرض فقط الكود الموجود ضمن خيار "-e" كخط واحد.
التعبيرات العادية
استخدم التعابير المنطقية البسيطة
عدة تطابقات مدمجة مع "||" أسرع من الكبيرة التي تحتوي على "|".
استخدم التعبيرات المترجمة مسبقًا
بدلاً من استيفاء السلاسل في regexps (إلا إذا كانت السلسلة لن تتغير أبدًا
واستخدمت المعدل "o"، وقم بترجمة regexp مسبقًا باستخدام "qr//" واستيفاء ذلك.
يستخدم (؟:...)
إذا كنت لا تستخدم ما يطابق المجموعة، فلا تجعل Perl يحفظه بـ "(...)".
مرساة في بداية السلسلة
لا تجعل Perl يبحث في السلسلة بأكملها، إذا كنت تريد التطابق فقط في
البداية.
لا ترسو في النهاية بعد الجشع
إذا كان لديك "*" أو "+" من شأنه أن يتطابق حتى نهاية السلسلة، فلا تضع "$" بعد ذلك
هنا.
استخدم آر ///
وهذا أسرع بمرتين من s/// عندما يكون قابلاً للتطبيق.
وظائف
تجنب اتجاه الكائن
يكون البحث عن الطريقة الديناميكية أبطأ في أي لغة، كما أن لغة Perl يمكن كتابتها بشكل فضفاض
لا تفعل ذلك أبدًا في وقت الترجمة. فلا تستخدمه إلا إذا كنت بحاجة إلى الاستفادة منه
تعدد الأشكال عن طريق الميراث. يتم ترتيب طرق الاتصال التالية من الأبطأ
إلى الأسرع:
$o->method(...); # تم البحث في فئة $o و@ISA
فئة::طريقة( $o, ... ); # وظيفة ثابتة، مكدس جديد
الفئة::الطريقة $o, ...; # وظيفة ثابتة، مكدس جديد، تم التحقق منه في وقت الترجمة
&الفئة::طريقة; # وظيفة ثابتة، إعادة استخدام المكدس
هذا النموذج الأخير ممكن دائمًا إذا كانت الطريقة (أو الوظيفة العادية) لا تأخذ أي وسائط. لو
يستغرق الأمر حججًا، احذر من عدم تقديم أي شيء اختياري عن غير قصد
تلك! إذا كنت تستخدم هذا النموذج كثيرًا، فمن الأفضل متابعة الحد الأدنى والحد الأقصى
عدد الوسائط التي يمكن أن تتخذها كل دالة. إعادة استخدام المكدس مع الوسائط الإضافية هو
لا مشكلة، سيتم تجاهلهم.
لا تقم بتعديل المكدس
تم العثور على الخطيئة التالية بشكل متكرر حتى في مستند Perl:
بلدي $ الذاتي = التحول ؛
ما لم يكن لديك سبب وجيه لذلك، استخدم هذا:
my( $self, $x, $y, @z ) = @_;
استخدام عدد قليل من الوظائف والوحدات
كل وظيفة (والتي تتضمن للأسف ثوابت) تشغل أكثر من 1 كيلو بايت لأنها مجرد
وجود. مع كل وحدة تتطلب وحدات أخرى، معظمها لا تحتاج إليه أبدًا، ذلك
يمكن أن تضيف ما يصل. لا تستخدم وحدة نمطية كبيرة، فقط لاستبدال سطرين من كود Perl بـ
استدعاء وظيفة واحدة أكثر أناقة.
إذا كان لديك دالة يتم استدعاؤها في مكان واحد فقط، وسيظل الاثنان معًا
باختصار إلى حد معقول، قم بدمجها مع التعليقات المناسبة.
ليس لديك دالة واحدة فقط تستدعي أخرى بنفس الوسائط. الاسم المستعار بدلا من ذلك:
*الاسم المستعار = \&function;
مكالمات جماعية للطباعة
تعتبر المكالمات الفردية للطباعة أو الطباعة باستخدام وسائط منفصلة باهظة الثمن. يبني
قم بتخزين السلسلة في الذاكرة وطباعتها دفعة واحدة. إذا كان بإمكانك تجميع أكثر من 3 كيلو بايت،
sywrite أكثر كفاءة.
بيرل -MBenchmark -we 'timethis -10, sub { print STDERR $_ for 1..5 }' 2>/dev/null
بيرل -MBenchmark -we 'timethis -10, sub { print STDERR 1..5 }' 2>/dev/null
Perl -MBenchmark -we 'timethis -10, sub { my $str = ""; $str .= $_ لـ 1..5; اطبع STDERR $str }' 2>/dev/null
منوع
تجنب التجزئة
تصبح لغة Perl بطيئة جدًا مع العديد من التجزئة الصغيرة. إذا لم تكن بحاجة إليها، فاستخدم شيئًا ما
آخر. يعمل اتجاه الكائن أيضًا على المصفوفة، باستثناء الأعضاء
لا يمكن الوصول إليها بالاسم. ولكن يمكنك استخدام الثوابت الرقمية لتسمية الأعضاء.
من أجل المقارنة نستخدم مفاتيح رقمية عادية هنا:
$i = 0; %a = Map +($i++, $_), "a".."j"; timethis -10, sub { $b = $a{int rand 10} }
@a = "a".."j"; timethis -10, sub { $b = $a[rand 10] }
$i = 0; %a = Map +($i++, $_), "a".."j"; timethis -10, sub { $b = $a{int rand 10} }
@a = "a".."j"; timethis -10, sub { $b = $a[rand 10] }
استخدم مفاتيح int لمجموعات المرجع
عندما تحتاج إلى تمثيل مرجعي فريد، على سبيل المثال لمجموعة العمليات ذات التجزئة، استخدم
يكون النموذج الصحيح للمراجع أسرع بثلاث مرات من استخدام النموذج الافتراضي المطبوع
تمثيل السلسلة. تحذير: إصدار HP/UX 64bitall من Perl، على الأقل يصل إلى
يحتوي الإصدار 5.8.8 على وظيفة "int" بها أخطاء، حيث لا تعمل هذه الوظيفة بشكل موثوق. هناك شكل سداسي عشري
لا يزال أسرع قليلاً من السلاسل الافتراضية. في الواقع يمكن أن يكون هذا أسرع
من stringified int، اعتمادًا على الإصدار أو ربما تكوين Perl. اعتبارا من
5.8.1 هناك أيضًا ما يعادله ولكن نأمل أن يكون موثوقًا به Scalar::Util::refaddr
@list = Map { Bless { $_ => 1 }, "someclass" } 0..9; بلدي( %أ، %b );
timethis -10, sub { $a{$_} = 1 لـ @list };
timethis -10, sub { $b{int()} = 1 لـ @list };
timethis -10, sub { $b{sprintf '%x', $_} = 1 لـ @list };
timethis -10, sub { $b{refaddr $_} = 1 لـ @list };
يوجد أيضًا sprintf '%p' والذي من المفترض أن يُخرج مؤشرًا، ولكن يعتمد على ذلك
يؤدي التعبير إلى نفس المرجع، وتحصل على قيم مختلفة، لذلك لا فائدة منه.
حذار من السلاسل
يعد Perl سيئًا جدًا في نسخ السلاسل دائمًا، حتى لو كنت لن تقوم بتعديلها أبدًا
هم. هذا يهدر وحدة المعالجة المركزية والذاكرة. حاول تجنب ذلك حيثما أمكن ذلك بشكل معقول.
إذا كانت السلسلة عبارة عن معلمة دالة وكان طول الدالة متواضعًا، فلا تنسخها
السلسلة في متغير "my"، وقم بالوصول إليها باستخدام $_[0] وقم بتوثيق الوظيفة جيدًا.
وفي أماكن أخرى، يمكن لميزة الاسم المستعار "لـ(كل)" أن تساعد. أو مجرد استخدام المراجع ل
السلاسل، والتي هي سريعة للنسخ. إذا تأكدت بطريقة ما من تخزين نفس السلاسل
مرة واحدة فقط، يمكنك إجراء مقارنة عددية للمساواة.
تجنب عمليات البت
إذا كان لديك أنماط بت منفصلة، يمكنك إضافتها بدلاً من إضافتها. التحول
يمكن إجراء الضرب أو القسمة على عدد صحيح. الاحتفاظ بالأدنى فقط
يمكن تحقيق البتات باستخدام modulo.
أعضاء التجزئة المنطقية المنفصلة أسرع من حشو كل شيء في عدد صحيح
عمليات البت أو في سلسلة تحتوي على "vec".
استخدام ترتيب العمليات المنطقية
إذا كنت تهتم فقط بما إذا كان التعبير صحيحًا أم خطأ، فتحقق من الأشياء الرخيصة، مثل
المتغيرات المنطقية، أولاً، ووظائف الاستدعاء أخيرًا.
استخدم undef بدلاً من 0
فهو يستهلك ذاكرة أقل بنسبة قليلة، على الأقل كقيم تجزئة أو قائمة. لا يزال بإمكانك
الاستعلام عنه باعتباره منطقيا.
بلدي %x؛ $x{$_} = 0 لـ 0..999_999؛ نظام "ps -ovsz $$"
بلدي %x؛ undef $x{$_} لـ 0..999_999؛ نظام "ps -ovsz $$"
@x = (0) x 999_999; نظام "ps -ovsz $$"
@x = (undef) x 999_999; نظام "ps -ovsz $$"
اختر ل أو الخريطة
هذه بالتأكيد ليست متكافئة. اعتمادًا على استخدامك (أي القائمة و
تعقيد التعليمات البرمجية الخاصة بك)، قد يكون أحدهما أو الآخر أسرع.
@l = 0..99;
ل(0..99_999) { الخريطة $a = " $_ ", @l }
ل(0..99_999) { الخريطة $a = " $_ ", 0..99 }
ل(0..99_999) { $a = " $_ " لـ @l }
لـ (0..99_999) { $a = " $_ " لـ 0..99 }
لا تستخدم الاسم المستعار $_
على الرغم من أنها مريحة، إلا أنها باهظة الثمن إلى حد ما، حتى أن نسخ السلاسل المعقولة يكون كذلك
أسرع. المثال الأخير أسرع بمرتين من المثال الأول "for".
بلدي $x = "abcdefg"; بلدي $ ب = 0؛
for( "$x" ) { $b = 1 - $b if /g/ } # النسخ مطلوب فقط في حالة التعديل.
من أجل( $x ) { $b = 1 - $b إذا /g/ }
local *_ = \$x; $b = 1 - $b إذا /g/;
محلي $_ = $x; $b = 1 - $b إذا /g/; # نسخة أرخص من الاسم المستعار.
$y = $x; $b = 1 - $b إذا $y =~ /g/;
استخدم perl_performance عبر الإنترنت باستخدام خدمات onworks.net