Domanda

boolean a = false, b = true;
if ( a && b ) { ... };

Nella maggior parte delle lingue, b non verrà valutato perché a è falso così a && b non può essere vero.La mia domanda è: il cortocircuito non sarebbe più lento in termini di architettura?In una pipeline, ti fermi mentre aspetti di ottenere il risultato di a per determinare se b deve essere valutato o no?Sarebbe meglio invece fare se nidificati?Anche questo aiuta?

Inoltre, qualcuno sa come viene generalmente chiamata la valutazione di cortocircuito?Questa domanda è nata dopo aver scoperto che il mio amico programmatore non aveva mai sentito parlare di valutazione del cortocircuito e ha affermato che non è comune, né si trova in molte lingue, ed è inefficiente nella pipeline.Non sono sicuro dell'ultimo, quindi chiedo a voi gente!

Ok, penso a un esempio diverso per spiegare forse da dove potrebbe venire il mio amico.Egli ritiene che, valutando in parallelo un'affermazione come la seguente:

(a) if ( ( a != null ) && ( a.equals(b) ) ) { ... }

manderà in crash il sistema, un'architettura che non ha cortocircuiti (e quindi non consente istruzioni come quelle sopra) sarebbe più veloce nell'elaborare istruzioni come queste:

(b) if ( ( a == 4 ) && ( b == 5 ) )

poiché se non potesse fare (a) in parallelo, non potrebbe fare (b) in parallelo.In questo caso, un linguaggio che consente il cortocircuito è più lento di uno che non lo consente.

Non so se sia vero o no.

Grazie

È stato utile?

Soluzione

Le espressioni booleane in cortocircuito sono esattamente equivalenti a un insieme di if annidati, quindi sono efficienti quanto lo sarebbero.

Se b non ha effetti collaterali, può comunque essere eseguito in parallelo con a (per qualsiasi valore di "in parallelo", incluso il pipelining).

Se b ha effetti collaterali che l'architettura della CPU non può annullare quando la previsione del ramo fallisce, allora sì, ciò potrebbe richiedere ritardi che non ci sarebbero se entrambi i lati fossero sempre valutati.Quindi è qualcosa a cui prestare attenzione se mai scopri che gli operatori di cortocircuito stanno creando un collo di bottiglia nelle prestazioni nel tuo codice, ma non vale la pena preoccuparsi altrimenti.

Ma il cortocircuito viene utilizzato tanto per controllare il flusso quanto per risparmiare lavoro non necessario.È comune tra le lingue che ho usato, ad esempio l'idioma Perl:

open($filename) or die("couldn't open file");

l'idioma della shell:

do_something || echo "that failed"

o l'idioma C/C++/Java/etc:

if ((obj != 0) && (obj->ready)) { do_something; } // not -> in Java of course.

In tutti questi casi è necessario cortocircuitare, in modo che l'RHS venga valutato solo se l'LHS lo impone.In questi casi non ha senso confrontare le prestazioni con un codice alternativo sbagliato!

Altri suggerimenti

La valutazione del cortocircuito viene tradotta in rami in linguaggio assembly allo stesso modo delle istruzioni if ​​(i rami sono fondamentalmente un goto), il che significa che non sarà più lento delle istruzioni if.

I rami in genere non bloccano la pipeline, ma il processore indovinerà se il ramo è stato preso o meno e, se il processore ha torto, dovrà eliminare tutto ciò che è accaduto da quando ha fatto l'ipotesi sbagliata dalla pipeline.

La valutazione del cortocircuito è anche il nome più comune e si trova nella maggior parte delle lingue in una forma o nell'altra.

Onestamente non me ne preoccuperei.Testare un valore booleano lo è davvero veloce.Il cortocircuito diventa interessante/utile solo quando la seconda espressione ha effetti collaterali:

if ( ConfirmAction() && DestroyAllData() )
   Reboot();

...o dipende dal primo test:

if ( myDodgyVar != null && myDodgyVar.IsActive() )
   DoSomethingWith(myDodgyVar);

Lingue che supportano il cortocircuito:

Ada, Eiffel, ALGOL 68, C1, C++, C#, Java, R, Erlang, Standard ML, Javascript, MATLAB, Lisp, Lua, Scheme, OCaml, Haskell, Pascal,Perl, Ruby, PHP, Python, Smalltalk, Visual Basic .NETTO

Preso da Valutazione del cortocircuito

VB.Net ha una sintassi diversa a seconda che si voglia o meno cortocircuitare o meno.Per motivi preesistenti, il comportamento predefinito è quello di non cortocircuitare.La sintassi è la seguente

Non cortocircuito

IF A And B THEN
    ...
END IF

Corto circuito

IF A AndAlso B THEN
    ...
END IF

Puoi usare Or / OrElse se vuoi cortocircuitare un'istruzione OR.Il che è davvero bello in situazioni come la seguente

If MyObj IsNot Nothing AndAlso MyObj.Value < SomeValue Then
    ....
End If

Personalmente, anche se capisco che un cortocircuito può accelerare le cose, non è sicuramente qualcosa di ovvio semplicemente guardando il codice.Ho potuto vedere uno sviluppatore inesperto confuso dal comportamento.Sembra addirittura che qualcosa possa accadere o meno a seconda dei flag del compilatore per il livello di ottimizzazione.Mi piace il modo in cui VB è dettagliato riguardo al comportamento che desideri effettivamente ottenere.

Innanzitutto, il tuo amico ha torto.La valutazione di cortocircuito (nota anche come valutazione minima) è disponibile nella maggior parte dei linguaggi ed è migliore dei if nidificati per i linguaggi paralleli (nel qual caso la prima delle condizioni restituite farà sì che l'esecuzione continui)

In ogni caso, anche in un linguaggio semplice e non parallelo, non vedo quanto gli if annidati sarebbero più veloci poiché l'esecuzione si bloccherebbe fino alla valutazione della prima condizione.

Come può un annidamento se non uno stallo?In realtà se aeb sono entrambe variabili e non espressioni con effetti collaterali, possono essere caricate in parallelo da un buon compilatore.Non c'è alcun vantaggio nell'utilizzare più if se non aumentare il numero di righe.In realtà, questo sarebbe il peggior tipo di ripensamento di un compilatore.

Si chiama valutazione del cortocircuito.

Un utile cortocircuito che utilizzo è qualcosa del genere:

if (a != null && a.equals(somevalue)) {
    ... do something.
}

Questo è, a mio parere, molto leggibile e funziona abbastanza bene.In generale, cerco di evitare troppi annidamenti perché portano a codice brutto.

Tutta la mia opinione però.

La maggior parte dei linguaggi effettua una valutazione in cortocircuito delle espressioni booleane.L'ho sempre sentito parlare di valutazione del cortocircuito.

L'esempio nella domanda è un esempio piuttosto semplicistico che in realtà non fornisce molti vantaggi in termini di prestazioni.Il vantaggio in termini di prestazioni si verifica quando le espressioni sono complesse da valutare.

Come esempio di quando questo sarebbe utile, immagina un programma di gioco che abbia qualcosa del tipo:

if (someObject.isActive() && someOtherObject.isActive() && CollisionDetection.collides(someObject, someOtherObject) {
  doSomething();
}

In questo caso il rilevamento delle collisioni è molto più costoso dei controlli attivi.Ci sarebbe un aumento significativo delle prestazioni se ci fossero molti oggetti inattivi nel sistema.

Il cortocircuito o la valutazione minima è solo zucchero sintattico per se nidificati.Supporre che sia inefficiente o che causi stalli è un caso di ottimizzazione prematura.A questo punto, la maggior parte dei compilatori è abbastanza intelligente da interpretare e ottimizzare correttamente queste affermazioni.L'utilizzo di queste istruzioni può ridurre notevolmente la nidificazione e quindi migliorare la leggibilità del codice, che dovrebbe essere il tuo obiettivo numero uno.

Per quanto riguarda l'efficienza o meno del cortocircuito, è improbabile che il pipeline abbia un impatto significativo sulle prestazioni.Nelle situazioni in cui potrebbe avere un impatto, non c'è nulla che impedisca al compilatore di testare più condizioni in parallelo purché questi test non abbiano effetti collaterali.Inoltre, le moderne CPU dispongono di diversi meccanismi utili per migliorare le prestazioni della pipeline del codice ramificato.

Gli if nidificati avranno lo stesso effetto del cortocircuito di &&.

"Valutazione di cortocircuito" è il nome più comune per questo, e il tuo amico ha torto sul fatto che sia raro;è molto comune.

Non so nulla di pipeline, ma la valutazione del cortocircuito è una caratteristica comune di molti linguaggi (ed è anche il nome con cui la conosco).In C, && e gli altri operatori definiscono a punto di sequenza proprio come il ;l'operatore lo fa, quindi non vedo come la valutazione del cortocircuito sia meno efficiente rispetto al semplice utilizzo di più istruzioni.

ne ho sentito parlare solo come cortocircuito.in una pipeline l'operazione successiva non dipende dal risultato dell'istruzione if?se così fosse, sarebbe più ottimizzato, quindi non dovrebbe testare due valori ogni volta.

Un singolo thread è sequenziale, quindi se hai due if il primo verrà ovviamente valutato prima del secondo, quindi non riesco a vedere alcuna differenza al riguardo.Utilizzo l'operatore condizionale AND (che è ciò che && viene chiamato afaik) molto più degli if annidati.Se voglio controllare qualcosa che potrebbe richiedere del tempo per essere valutato, faccio prima il test più semplice e poi quello più difficile dopo il condizionale e.

a = obj.somethingQuickToTest() && obj.somethingSlowToTest();

non sembra essere diverso da

a = false;
if(obj.somethingQuickToTest())
   a = obj.somethingSlowToTest();

A seconda del contesto può anche essere chiamato "Guardia".

E l'ho visto in quasi tutte le lingue in cui ho lavorato, quasi una dozzina.

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