Devo pensare al codice macchina compilato quando scrivo il mio codice?


20

Ad esempio ho il seguente codice:

auto z = [](int x) -> int {
    if (x > 0) {
        switch (x) {
            case 2: return 5;
            case 3: return 6;
            default: return 1;
            }
        }
    return 0;
    };

E dopo lo chiamo più volte. Nel codice asm vedo chiamate esterne con lambda .... qualcosa ... Non sta diventando facile da leggere e penso che possa anche causare prestazioni. Quindi forse vinco in meta-programmazione ma perdo in debug asm e prestazioni? Dovrei evitare le funzionalità del linguaggio moderno, le macro e altri aspetti della meta-programmazione per essere sicuro delle prestazioni e della semplicità del debug?


1
A seconda della versione del compilatore e della sua libreria standard in bundle, lambda potrebbe effettivamente essere implementato in modo inefficiente. Vedi questa domanda su StackOverflow. Tuttavia, la responsabilità del miglioramento dovrebbe spettare al fornitore del compilatore.
rwong

15
Non è necessario eseguire il debug del codice assembly, a meno che non ci si trovi in ​​un percorso critico per le prestazioni. Inoltre, "clean code"! = "Buone prestazioni".
BЈовић

Correggi il tuo rientro, per favore. Ho provato a farlo, ma sembra che non puoi modificare solo gli spazi bianchi.
Christoffer Hammarström l'

3
@Heather: sembra che tu stia usando lo stile Ratliff , che non ho mai visto prima e che trovo difficile da leggere. È sicuramente uno dei meno conosciuti. La mia impressione era che non avessi indentato correttamente. Non importa quindi se lo trovi leggibile, non sono d'accordo.
Christoffer Hammarström,

1
Il ifcodice è completamente ridondante nel codice di esempio e mentre il compilatore probabilmente capirà che non c'è motivo di tentare una brutta previsione del ramo.
dmckee,

Risposte:


59

Devo pensare al codice macchina compilato quando scrivo il mio codice?

No , non quando scrivi il tuo codice la prima volta e non soffri di problemi di prestazioni reali e misurabili. Per la maggior parte delle attività, questo è il caso standard. Pensare troppo presto all'ottimizzazione si chiama "ottimizzazione prematura", e ci sono buone ragioni per cui D. Knuth l'ha definita "la radice di tutti i mali" .

, quando si misura un collo di bottiglia delle prestazioni reale e dimostrabile e si identifica quel costrutto lambda specifico come causa principale. In questo caso, può essere una buona idea ricordare la "legge delle astrazioni che perdono " di Joel Spolsky e pensare a cosa potrebbe accadere a livello di asm. Ma attenzione, potresti essere stupito di quanto piccolo sarà l'aumento delle prestazioni quando sostituirai un costrutto lambda con un costrutto linguistico "non così moderno" (almeno, quando usi un compilatore C ++ decente).


2
+1 Conciso, preciso e facile da seguire come al solito Doc, felice di averti qui.
Jimmy Hoffa l'

Concordato, risposta molto chiara.
cnd

8

La scelta tra lambda e la classe functor è un compromesso.

Il guadagno di lambda è principalmente sintattico, riducendo al minimo la quantità di boilerplate e consentendo la scrittura in linea del codice correlato concettualmente, all'interno della funzione che lo utilizzerà (immediatamente o successivamente).

Per quanto riguarda le prestazioni, questo non è peggio di una classe functor , che è una struttura o classe C ++ che contiene un singolo "metodo". In effetti, i compilatori trattano lambda non diversamente da una classe di funzioni generata dal compilatore dietro la scena.

// define the functor method somewhere
struct some_computer_generated_gibberish_0123456789
{
    int operator() (int x) const
    {
        if (x == 2) return 5;
        if (x == 3) return 6;
        return 0;
    }
};

// make a call
some_computer_generated_gibberish_0123456789 an_instance_of_0123456789;
int outputValue = an_instance_of_0123456789(inputValue);

Nel tuo esempio di codice, dal punto di vista delle prestazioni non è diverso da una chiamata di funzione, perché quella classe di funzioni non ha uno stato (perché ha una clausola di acquisizione vuota), quindi non richiede allocazione, costruttore o distruzione.

int some_computer_generated_gibberish_0123456789_method_more_gibberish(int x)
{
    if (...) return ...;
    return ...;
}

Il debug di qualsiasi codice C ++ non banale utilizzando un disassemblatore è sempre stato un compito difficile. Questo è vero con o senza l'utilizzo di lambda. Ciò è causato dalla sofisticata ottimizzazione del codice da parte del compilatore C ++ che ha comportato il riordino, l'interleaving e l'eliminazione del codice morto.

L'aspetto del nome è alquanto sgradevole e il supporto del debugger per lambda è ancora agli inizi . Si può solo sperare che il supporto del debugger migliorerà nel tempo.

Attualmente, il modo migliore per eseguire il debug del codice lambda è utilizzare un debugger che supporti l'impostazione di punti di interruzione a livello di codice sorgente, ovvero specificando il nome del file di origine e il numero di riga.


3

Per aggiungere alla risposta di @DocBrown, ricorda che oggigiorno le CPU sono economiche ma il lavoro è costoso.

Nel costo complessivo di un programma, l'hardware è di solito banale rispetto al costo di manutenzione, che è di gran lunga la parte più costosa di un progetto tipico (anche più del suo sviluppo).

Pertanto, il codice deve ottimizzare la manutenzione sopra ogni altra cosa, tranne quando le prestazioni sono fondamentali (e anche in questo caso è necessario considerare la manutenzione).


Solo parzialmente vero. Se il tuo codice esegue O (n ^ 2) (quadratico) e puoi renderlo qualcosa di meglio dire O (log (n)) (logaritmico), l'hardware non avrà mai un aumento delle prestazioni tanto quanto la modifica del codice. Nel caso specificato dal poster originale questo è molto improbabile.
gnash117,

@ gnash117 - sì, hai ragione se il codice deve essere eseguito più volte; grazie per averlo sottolineato. In tali casi, documentare chiaramente il codice lo manterrà mantenibile, consentendo nel contempo il miglioramento delle prestazioni.
Paddy Landau,

"il lavoro è costoso" - Corretto. Il tempo dei tuoi clienti è molto importante e spesso costoso.
Cerad,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.