Principi di programmazione per quanto riguarda l'efficienza del software (computazionale) e l'uso di variabili

8

Sono uno psicologo di formazione classica, non un programmatore, quindi a volte mi sfuggono gli aspetti più avanzati della programmazione, in particolare per quanto riguarda l'efficienza del programma e / o determinate migliori pratiche, in questo caso per quanto riguarda l'uso delle variabili.

Ecco alcuni pseudo-codice:

var a;
var b;
var c;
function GetSomeInformation() {
    returns "XYZ";
}

a = GetSomeInformation();
b = GetSomeInformation();
c = GetSomeInformation();

Quindi la mia domanda è:
È più o meno efficiente (o la stessa cosa) memorizzare i dati in una variabile una volta e fare riferimento a ciò rispetto alle chiamate ripetute alla stessa funzione?

I.E., questo codice è più efficiente?

var results = GetSomeInformation();
a = results;
b = results;
c = results;

In tal caso, questo guadagno o perdita di efficienza è generalmente la stessa in tutte le lingue o varia in base alla lingua? Ci sono soglie dove diventa preferibile assegnare un nome a una variabile anziché utilizzare una chiamata a funzioni ripetute o viceversa? Quali aspetti potrebbero cambiare la sua efficienza (ad esempio, c'è una differenza se si tratta di una funzione membro di una classe rispetto a una funzione regolare nell'ambito globale)? ecc.

Se possibile, mi piacerebbe sapere in che modo tale nozione si applica alle finestre di dialogo C ++ / MFC, come è emerso quando stavo scrivendo del codice in quel framework.

// define pointers to the items in my form
CListBox *pLISTBOX = (CListBox*) GetDlgItem(LISTBOX);
CStatic *pSTATIC_A = (CStatic*) GetDlgItem(STATIC_A);
CStatic *pSTATIC_B = (CStatic*) GetDlgItem(STATIC_B);
CEdit *pEDIT_BOX_A = (CEdit*) GetDlgItem(EDIT_BOX_A);
CEdit *pEDIT_BOX_B = (CEdit*) GetDlgItem(EDIT_BOX_B);
int SelectedIndex = pLISTBOX->GetCurSel();
pSTATIC_A->SetWindowText(pLISTBOX->GetItemData(SelectedIndex));
pSTATIC_B->SetWindowText(pLISTBOX->GetItemData(SelectedIndex));
pEDIT_BOX_A->SetWindowText(pLISTBOX->GetItemData(SelectedIndex));
pEDIT_BOX_B->SetWindowText(pLISTBOX->GetItemData(SelectedIndex));
    
posta stoicfury 06.02.2013 - 23:44
fonte

5 risposte

10

Per rispondere alla tua domanda: In genere più è efficiente per memorizzare i dati in una variabile e fare riferimento a ciò. Ulteriori variabili locali sono economiche.

Iniziando con un semplice esempio, supponiamo di avere il frammento di codice:

x = 5;
y = x*x + 1;
z = x*x + 2;

Se guardi il codice sopra e fai finta di essere la CPU che lo esegue passo dopo passo, la CPU farebbe la moltiplicazione due volte con lo stesso valore di x . È quasi sempre meno efficiente rispetto alla moltiplicazione una volta:

x = 5;
x2 = x*x;
y = x2 + 1;
z = x2 + 2;

Ora, i compilatori moderni hanno quasi sempre un'ottimizzazione chiamata eliminazione di sottoespressione comune , che avrà lo stesso effetto di estrarre x2 come nell'esempio precedente. Quindi spesso non devi preoccuparti di questo, perché il compilatore ha la schiena.

Detto questo, l'uso di una variabile come x2 potrebbe ridurre sostanzialmente la complessità delle seguenti righe, quindi non c'è niente di sbagliato nell'introdurre una variabile come quella per motivi di leggibilità.

Nel caso del codice MFC, stai chiamando ripetutamente pLISTBOX->GetItemData(SelectedIndex) . Poiché questa è una chiamata di funzione che effettua una chiamata nel sistema operativo per ottenere ulteriori dati, il compilatore non può fare l'eliminazione di sottoespressione comune su quello. Invece, vorrei introdurre una nuova variabile, quindi devi fare una sola chiamata:

int SelectedIndex = pLISTBOX->GetCurSel();
const char *data = pLISTBOX->GetItemData(SelectedIndex);
pSTATIC_A->SetWindowText(data);
pSTATIC_B->SetWindowText(data);
pEDIT_BOX_A->SetWindowText(data);
pEDIT_BOX_B->SetWindowText(data);
    
risposta data 06.02.2013 - 23:52
fonte
3
  1. Sì, il secondo codice è leggermente più efficiente del primo codice, nella maggior parte delle lingue.
  2. Probabilmente non fa alcuna differenza pratica.
  3. Probabilmente fa fa la differenza nella leggibilità, quindi vai con il codice più pulito.

Inoltre, un buon compilatore (incluso JIT di Java) inline chiamerà ripetute chiamate di metodi e memorizzerà ripetutamente i valori usati, quindi i due esempi probabilmente finirebbero per essere comparabili.

Fai riferimento alle seguenti regole pratiche:

Fallo funzionare, fallo bene, fallo velocemente ... in questo ordine. - Kent Beck

La prima regola di ottimizzazione : no.

La seconda regola di ottimizzazione : Non ancora ...

La terza regola di ottimizzazione : profilo prima dell'ottimizzazione

L'ottimizzazione prematura è la radice di tutti i mali. - Donald Knuth

Nella maggior parte dei casi, > il 90% del tempo del tuo programma sarà speso in < 10% del codice, e senza profilare il tuo codice, non hai idea di quale sia il 10%. Quindi non preoccuparti nemmeno di questo fino a quando non ricevi feedback; è molto più prezioso ottimizzare per tempo del programmatore di tempo di esecuzione .

    
risposta data 06.02.2013 - 23:55
fonte
3

Di solito è più efficiente memorizzare un valore calcolato in una variabile locale, supponendo che il compilatore non lo abbia già ottimizzato per te. In effetti, a volte questo è incorporato in una funzione stessa, in una tecnica chiamata memoization .

Tuttavia, il più delle volte, il guadagno di efficienza è abbastanza piccolo da essere considerato trascurabile. La leggibilità dovrebbe essere di solito la tua preoccupazione principale dopo la correttezza.

Detto questo, l'uso di una variabile locale spesso lo rende anche più leggibile, offrendoti il meglio di entrambi i mondi. Usando il tuo esempio:

const char* text = pLISTBOX->GetItemData(SelectedIndex);
pSTATIC_A->SetWindowText(text);
pSTATIC_B->SetWindowText(text);
pEDIT_BOX_A->SetWindowText(text);
pEDIT_BOX_B->SetWindowText(text);

Questo è molto più chiaro per un lettore umano. Non solo non devi leggere quella lunga chiamata di funzione su ogni riga, è esplicitamente chiaro che tutti i widget stanno ricevendo esattamente lo stesso testo.

    
risposta data 07.02.2013 - 00:12
fonte
2

Le variabili sono essenzialmente gratuite, ma la chiamata alla funzione ha un costo sconosciuto, quindi vai sempre con la variabile.

    
risposta data 07.02.2013 - 00:02
fonte
1

Un principio generale che seguo è che se non so sapere come viene implementata una funzione, potrebbe essere costosa e se io so > che ho bisogno solo del valore di quella funzione una volta, lo memorizzo solo localmente. Il tuo esempio di codice diventerebbe quindi:

// define pointers to the items in my form
//...
int SelectedIndex = pLISTBOX->GetCurSel();
String text = pLISTBOX->GetItemData(SelectedIndex); //Ok, so maybe String isn't a valid type here but you get the idea...
pSTATIC_A->SetWindowText(text);
pSTATIC_B->SetWindowText(text);
pEDIT_BOX_A->SetWindowText(text);
pEDIT_BOX_B->SetWindowText(text);
    
risposta data 06.02.2013 - 23:53
fonte

Leggi altre domande sui tag