Domanda

Che tipo di implicazioni sulle prestazioni ci sono da considerare quando si usano le istruzioni try-catch in php 5?

Ho letto sul web alcune informazioni vecchie e apparentemente contrastanti su questo argomento. Gran parte del framework con cui attualmente devo lavorare è stato creato su php 4 e manca di molte delle bellezze di php 5. Quindi, non ho molta esperienza di me stesso nell'uso di try-catchs con php.

È stato utile?

Soluzione

Una cosa da considerare è che il costo di un blocco try in cui non viene generata alcuna eccezione è una domanda diversa dal costo di lanciare e catturare un'eccezione.

Se si generano eccezioni solo in casi di fallimento, quasi sicuramente non ti interessano le prestazioni, dal momento che non fallirai molte volte per esecuzione del tuo programma. Se stai fallendo in un circuito stretto (a.k.a: sbattere la testa contro un muro di mattoni), la tua applicazione probabilmente ha problemi peggiori che essere lenti. Quindi non preoccuparti del costo di generare un'eccezione a meno che tu non sia in qualche modo costretto a usarli per un flusso di controllo regolare.

Qualcuno ha pubblicato una risposta parlando del codice di profilazione che genera un'eccezione. Non l'ho mai provato da solo, ma prevedo con sicurezza che questo mostrerà un successo molto più grande rispetto al semplice entrare e uscire da un blocco di prova senza lanciare nulla.

Un'altra cosa da considerare è che dove annidate chiama molti livelli di profondità, può anche essere più veloce fare un singolo tentativo ... prendere in alto piuttosto che controllare i valori di ritorno e propagare gli errori su ogni chiamata .

Al contrario di quella situazione, dove trovi che stai avvolgendo ogni chiamata nel suo tentativo try ... catch block, il tuo codice sarà più lento. E più brutto.

Altri suggerimenti

Ero annoiato e ho profilato quanto segue (ho lasciato fuori il codice di temporizzazione):

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

utilizzando due diversi loop:

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) {}
}

Con 1000000 viene eseguito sulla mia casella WinXP esegui apache e 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

Questi risultati sono stati coerenti e sono rimasti in proporzioni simili, indipendentemente dall'ordine in cui sono stati eseguiti i test.

Conclusione: l'aggiunta di codice per gestire le eccezioni rare non è più lenta del codice che ignora le eccezioni.

I blocchi try-catch non rappresentano un problema di prestazioni: il vero collo di bottiglia delle prestazioni deriva dalla creazione di oggetti eccezione.

Codice test:

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";
}

Risultati:

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

In genere, utilizzare un'eccezione per evitare errori imprevisti e utilizzare il controllo degli errori nel codice contro errori che fanno parte del normale stato del programma. Per illustrare:

  1. Record non trovato nel database - stato valido, dovresti controllare i risultati della query e inviare messaggi all'utente in modo appropriato.

  2. Errore SQL durante il tentativo di recuperare il record - errore imprevisto, il record potrebbe essere o non essere presente, ma si è verificato un errore del programma - questo è un buon posto per un'eccezione - errore di registro nel registro degli errori, e-mail all'amministratore la traccia dello stack e visualizza un cortese messaggio di errore all'utente avvisandolo che qualcosa è andato storto e ci state lavorando.

Le eccezioni sono costose, ma a meno che non gestiate l'intero flusso del programma utilizzandole, qualsiasi differenza di prestazioni non dovrebbe essere evidente all'uomo.

Non ho trovato nulla sulle prestazioni Try / Catch su Google ma un semplice test con un errore di lancio del ciclo invece di un'istruzione IF produce 329 ms contro 6 ms in un ciclo di 5000.

Mi dispiace postare su un messaggio molto vecchio, ma ho letto i commenti e in qualche modo non sono d'accordo, la differenza potrebbe essere minima con un semplice pezzo di codice o potrebbe essere trascurabile dove vengono utilizzati Try / Catch per parti specifiche del codice che non sono sempre prevedibili, ma credo anche (non testato) che un semplice:

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

è più veloce di

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

Credo anche (non testato) che a:

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

è più costoso di un IF aggiuntivo nel codice

Questa è un'ottima domanda!

L'ho provato molte volte e non ho mai visto alcun problema di prestazioni ;-) Era vero 10 anni fa in C ++ ma penso che oggi lo abbiano migliorato molto da quando è così utile e pulito.

Ma ho ancora paura di circondare il mio primo punto di ingresso:

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

Non ho provato con molte funzioni call e include grandi .... Qualcuno l'ha già testato completamente?

In generale, sono costosi e non utili in PHP.

Dato che è un linguaggio di espressioni controllate, DEVI catturare tutto ciò che genera un'eccezione.

Quando si ha a che fare con un codice legacy che non viene lanciato e un nuovo codice che lo fa, si crea solo confusione.

Buona fortuna!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top