سؤال

ما نوع الآثار المترتبة على الأداء التي يجب مراعاتها عند استخدام عبارات محاولة الالتقاط في PHP 5؟

لقد قرأت بعض المعلومات القديمة والتي تبدو متضاربة حول هذا الموضوع على الويب من قبل.تم إنشاء الكثير من إطار العمل الذي يتعين علي العمل معه حاليًا على php 4 ويفتقر إلى العديد من التفاصيل الدقيقة الموجودة في php 5.لذا، ليس لدي خبرة كبيرة في استخدام أدوات المحاولة مع php.

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

المحلول

هناك شيء واحد يجب مراعاته وهو أن تكلفة كتلة المحاولة التي لا يتم طرح أي استثناء فيها هي سؤال مختلف عن تكلفة طرح الاستثناء فعليًا والتقاطه.

إذا تم طرح الاستثناءات فقط في حالات الفشل، فمن المؤكد أنك لا تهتم بالأداء، لأنك لن تفشل مرات عديدة في كل تنفيذ لبرنامجك.إذا كنت تفشل في حلقة ضيقة (ويعرف أيضًا باسم:اصطدام رأسك بجدار من الطوب)، فمن المحتمل أن يواجه تطبيقك مشكلات أسوأ من كونه بطيئًا.لذلك لا تقلق بشأن تكلفة طرح استثناء إلا إذا كنت مجبرًا بطريقة ما على استخدامه للتحكم المنتظم في التدفق.

نشر شخص ما إجابة تتحدث عن رمز ملف التعريف الذي يطرح استثناءً.لم أختبره بنفسي مطلقًا، لكنني أتوقع بثقة أن هذا سيُظهر أداءً أكبر بكثير من مجرد الدخول والخروج من كتلة المحاولة دون رمي أي شيء.

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

في عكس هذا الموقف، حيث تجد أنك تقوم بتغليف كل مكالمة في كتلة المحاولة...التقاط الخاصة بها، فإن التعليمات البرمجية الخاصة بك ستكون أبطأ.وأقبح.

نصائح أخرى

لقد شعرت بالملل وقمت بتوصيف ما يلي (تركت رمز التوقيت خارجًا):

function no_except($a, $b) { 
    $a += $b;
    return $a;
}
function except($a, $b) { 
    try {
        $a += $b;
    } catch (Exception $e) {}
    return $a;
}

باستخدام حلقتين مختلفتين:

echo 'no except with no surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    no_except(5, 7);
}
echo 'no except with surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    try {
        no_except(5, 7);
    } catch (Exception $e) {}
}
echo 'except with no surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    except(5, 7);
}
echo 'except with surrounding try';
for ($i = 0; $i < NUM_TESTS; ++$i) {
    try {
        except(5, 7);
    } catch (Exception $e) {}
}

مع 1000000 عملية تشغيل على صندوق WinXP الخاص بي، قم بتشغيل Apache وPHP 5.2.6:

no except with no surrounding try = 3.3296
no except with surrounding try = 3.4246
except with no surrounding try = 3.2548
except with surrounding try = 3.2913

وكانت هذه النتائج متسقة وظلت بنسبة مماثلة بغض النظر عن ترتيب إجراء الاختبارات.

خاتمة:إن إضافة التعليمات البرمجية للتعامل مع الاستثناءات النادرة ليس أبطأ من التعليمات البرمجية التي تتجاهل الاستثناءات.

لا تمثل كتل Try-catch مشكلة في الأداء - فالعائق الحقيقي للأداء يأتي من إنشاء كائنات استثناء.

رمز الاختبار:

function shuffle_assoc($array) { 
    $keys = array_keys($array);
    shuffle($keys);
    return array_merge(array_flip($keys), $array);
}

$c_e = new Exception('n');

function no_try($a, $b) { 
    $a = new stdclass;
    return $a;
}
function no_except($a, $b) { 
    try {
        $a = new Exception('k');
    } catch (Exception $e) {
        return $a + $b;
    }
    return $a;
}
function except($a, $b) { 
    try {
        throw new Exception('k');
    } catch (Exception $e) {
        return $a + $b;
    }
    return $a;
}
function constant_except($a, $b) {
    global $c_e;
    try {
        throw $c_e;
    } catch (Exception $e) {
        return $a + $b;
    }
    return $a;
}

$tests = array(
    'no try with no surrounding try'=>function() {
        no_try(5, 7);
    },
    'no try with surrounding try'=>function() {
        try {
            no_try(5, 7);
        } catch (Exception $e) {}
    },
    'no except with no surrounding try'=>function() {
        no_except(5, 7);
    },
    'no except with surrounding try'=>function() {
        try {
            no_except(5, 7);
        } catch (Exception $e) {}
    },
    'except with no surrounding try'=>function() {
        except(5, 7);
    },
    'except with surrounding try'=>function() {
        try {
            except(5, 7);
        } catch (Exception $e) {}
    },
    'constant except with no surrounding try'=>function() {
        constant_except(5, 7);
    },
    'constant except with surrounding try'=>function() {
        try {
            constant_except(5, 7);
        } catch (Exception $e) {}
    },
);
$tests = shuffle_assoc($tests);

foreach($tests as $k=>$f) {
    echo $k;
    $start = microtime(true);
    for ($i = 0; $i < 1000000; ++$i) {
        $f();
    }
    echo ' = '.number_format((microtime(true) - $start), 4)."<br>\n";
}

نتائج:

no try with no surrounding try = 0.5130
no try with surrounding try = 0.5665
no except with no surrounding try = 3.6469
no except with surrounding try = 3.6979
except with no surrounding try = 3.8729
except with surrounding try = 3.8978
constant except with no surrounding try = 0.5741
constant except with surrounding try = 0.6234

بشكل عام، استخدم استثناءً للحماية من حالات الفشل غير المتوقعة، واستخدم التحقق من الأخطاء في التعليمات البرمجية الخاصة بك ضد حالات الفشل التي تعد جزءًا من حالة البرنامج العادية.لتوضيح:

  1. لم يتم العثور على السجل في قاعدة البيانات - حالة صالحة، يجب عليك التحقق من نتائج الاستعلام ومراسلة المستخدم بشكل مناسب.

  2. خطأ SQL عند محاولة جلب السجل - فشل غير متوقع، قد يكون السجل موجودًا أو لا يكون موجودًا، ولكن لديك خطأ في البرنامج - وهذا مكان جيد للاستثناء - خطأ في السجل في سجل الأخطاء، وأرسل بريدًا إلكترونيًا إلى المسؤول لتتبع المكدس، واعرضه رسالة خطأ مهذبة للمستخدم تخبره بحدوث خطأ ما وأنك تعمل على إصلاحه.

الاستثناءات باهظة الثمن، ولكن ما لم تتعامل مع تدفق البرنامج بالكامل باستخدامها، فلن يكون أي اختلاف في الأداء ملحوظًا للإنسان.

لم أجد أي شيء في أداء Try/Catch على Google ولكن اختبارًا بسيطًا مع خطأ في إلقاء الحلقة بدلاً من عبارة IF ينتج عنه 329 مللي ثانية مقابل 6 مللي ثانية في حلقة تبلغ 5000.

نأسف للنشر في رسالة قديمة جدًا، لكنني قرأت التعليقات وأنا لا أوافق إلى حد ما، قد يكون الاختلاف ضئيلًا مع جزء بسيط من الأكواد، أو قد يكون قابلاً للإهمال حيث يتم استخدام Try/Catch لأجزاء محددة من التعليمات البرمجية التي ليست كذلك يمكن التنبؤ به دائمًا، لكنني أعتقد أيضًا (لم يتم اختباره) أن الأمر بسيط:

if(isset($var) && is_array($var)){
    foreach($var as $k=>$v){
         $var[$k] = $v+1;
    }
}

أسرع من

try{
    foreach($var as $k=>$v){
        $var[$k] = $v+1;
    }
}catch(Exception($e)){
}

وأعتقد أيضًا (لم يتم اختباره) أن:

<?php
//beginning code
try{
    //some more code
    foreach($var as $k=>$v){
        $var[$k] = $v+1;
    }
    //more code
}catch(Exception($e)){
}
//output everything
?>

أغلى من وجود IFs إضافية في الكود

هذا سؤال جيد جدا!

لقد اختبرت ذلك عدة مرات ولم أر أي مشكلة في الأداء أبدًا؛-) كان هذا صحيحًا منذ 10 سنوات في لغة C++ ولكن أعتقد اليوم أنهم قاموا بتحسينها كثيرًا منذ أن أصبحت مفيدة جدًا وأنظف.

لكنني ما زلت خائفًا من إحاطة نقطة دخولي الأولى بها:

try {Controller::run();}catch(...)

لم أختبر مع الكثير من استدعاء الوظائف وتشمل كبيرة ....هل قام أي شخص باختباره بالكامل بالفعل؟

بشكل عام، فهي باهظة الثمن وغير جديرة بالاهتمام في لغة PHP.

نظرًا لأنها لغة تعبيرات محددة، يجب عليك التقاط أي شيء يطرح استثناءً.

عند التعامل مع التعليمات البرمجية القديمة التي لا ترمي، والتعليمات البرمجية الجديدة التي تفعل ذلك، فإن ذلك يؤدي فقط إلى الارتباك.

حظ سعيد!

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