La programmazione modulare influisce sul tempo di calcolo?

19

Tutti dicono che dovrei rendere modulare il mio codice, ma non è meno efficiente se uso più chiamate al metodo piuttosto che meno, ma più grandi, metodi? Qual è la differenza tra Java, C o C ++?

Ho capito che è più facile modificare, leggere e capire, specialmente in un gruppo. Quindi la perdita di tempo di calcolo è insignificante rispetto ai benefici del codice in ordine?

    
posta fatsokol 29.07.2013 - 12:40
fonte

7 risposte

46

Sì, è irrilevante.

I computer sono motori di esecuzione instancabili e quasi perfetti che funzionano a velocità totalmente non paragonabili ai cervelli. Mentre c'è una quantità di tempo misurabile che una chiamata di funzione aggiunge al tempo di esecuzione di un programma, questo è nulla rispetto al tempo aggiuntivo necessario dal cervello della prossima persona coinvolta con il codice quando devono districare la routine illeggibile persino iniziare per capire come lavorarci. Puoi provare il calcolo per uno scherzo - supponi che il tuo codice debba essere mantenuto solo una volta , e questo solo aggiunge mezz'ora al tempo necessario per qualcuno a venire a termini con il codice. Prendi la velocità del tuo processore e calcola: quante volte il codice deve essere eseguito anche per sognare di compensare quello?

In breve, avere pietà della CPU è del tutto, del tutto fuorviato al 99,99% delle volte. Per i rari casi rimanenti, utilizzare profiler. Supponiamo che non tu possa individuare quei casi, ma non puoi.

    
risposta data 29.07.2013 - 13:43
fonte
22

Dipende.

Nel mondo glaciale-lento che è la programmazione Web, dove tutto avviene a velocità umana, programmazione metodica, in cui il costo della chiamata al metodo è paragonabile o superiore al costo dell'elaborazione fatta dal metodo, probabilmente non non importa.

Nel mondo della programmazione di sistemi embedded e dei gestori di interrupt per interrupt di alta qualità, è sicuramente importante. In quell'ambiente, i soliti modelli di "accesso alla memoria è economico" e "il processore è infinitamente veloce" si rompono. Ho visto cosa succede quando un programmatore orientato agli oggetti mainframe scrive il suo primo gestore di interrupt ad alta velocità. Non era carino.

Alcuni anni fa, stavo facendo non ricorsiva a 8 vie colorazione connettività blob in tempo reale FLIR immaginario, su quello che era in quel momento un processore decente. Il primo tentativo ha utilizzato una chiamata di subroutine e la chiamata di subroutine overhead ha mangiato il processore in modo attivo. (4 chiamate PER PIXEL x 64K pixel per frame x 30 frame al secondo = lo vedi). Il secondo tentativo ha cambiato la subroutine in una macro C, senza perdita di leggibilità, e tutto era rose.

Devi guardare DURO a quello che stai facendo e all'ambiente in cui lo farai.

    
risposta data 29.07.2013 - 17:32
fonte
11

Prima di tutto: i programmi in una lingua superiore devono essere letti dagli umani e non dalle macchine.

Quindi scrivi i programmi in modo che tu li capisca. Non pensare alle prestazioni (se hai seriamente problemi di perfomance, quindi profila la tua applicazione e migliora le prestazioni laddove è necessario).

Anche se è vero che chiamare un metodo o una funzione richiede un sovraccarico, non importa. Oggi i compilatori dovrebbero essere in grado di compilare il codice in un linguaggio macchina efficiente in modo che il codice generato sia efficiente per l'architettura di destinazione. Usa gli interruttori di ottimizzazione del tuo compilatore per ottenere il codice efficiente.

    
risposta data 29.07.2013 - 12:52
fonte
5

Tipicamente quando altrimenti avresti una grande funzione e la divideresti in molte di quelle più piccole, queste più piccole saranno inline perché l'unico svantaggio di inlining (ripetendo troppo le stesse istruzioni) non è rilevante in questo caso. Ciò significa che il tuo codice agirà come se avessi scritto una funzione di grandi dimensioni.

Se non sono in linea per qualche motivo e questo diventa un problema di prestazioni, allora dovresti considerare l'inlining manuale. Non tutte le applicazioni sono moduli CRUD collegati in rete con enormi latenze intrinseche.

    
risposta data 29.07.2013 - 17:31
fonte
2

Probabilmente non vi è alcun costo di calcolo. Di solito i compilatori / JIT per gli ultimi 10-20 anni si occupano perfettamente della funzione inlining. Per il C / C ++ di solito è limitato alle funzioni 'inlinable' (cioè la definizione della funzione è disponibile per il compilatore durante la compilazione - cioè è nell'intestazione dello stesso file) ma le tecniche correnti di LTO lo superano.

Se dovresti spendere tempo per l'ottimizzazione dipende dall'area su cui stai lavorando. Se ti occupi di applicazioni "normali" che trascorrono la maggior parte del tempo in attesa di input, probabilmente non dovresti preoccuparti delle ottimizzazioni a meno che l'applicazione non sia "lenta".

Anche in questi casi dovresti concentrarti su molte cose prima di eseguire la micro-ottimizzazione:

  • Dove sono i problemi? Di solito le persone hanno difficoltà a trovare gli hotspot mentre leggiamo il codice sorgente in modo diverso. Abbiamo un diverso rapporto tra i tempi operativi e li eseguiamo in sequenza mentre moderno processori non .
  • È necessario eseguire qualche calcolo ogni volta? Ad esempio, se modifichi un singolo parametro su migliaia, potresti voler calcolare solo una parte interessata anziché un intero modello.
  • Usi l'algoritmo ottimale? Il passaggio da O(n) a O(log n) potrebbe avere un impatto molto più grande di qualsiasi cosa tu possa ottenere con la micro-ottimizzazione.
  • Usi strutture adeguate? Supponiamo che tu stia utilizzando un List quando hai bisogno di HashSet , quindi hai O(n) ricerche quando potresti avere O(1) .
  • Usi il parallelismo in modo efficiente? Attualmente anche i telefoni cellulari possono avere 4 core o più potrebbe essere tentato di usare i thread. Tuttavia non sono un proiettile d'argento in quanto hanno un costo di sincronizzazione (non menzionando che se il problema è legato alla memoria non hanno comunque senso).

Anche se decidi che hai bisogno di eseguire micro-ottimizzazione (che in pratica significa che il tuo software è usato in HPC, incorporato o usato solo da molto un gran numero di persone - altrimenti il costo aggiuntivo di manutenzione superano i costi del computer) è necessario identificare gli hotspot (kernel) che si desidera accelerare. Ma probabilmente dovresti:

  1. Conosci esattamente la piattaforma su cui stai lavorando
  2. Conosci esattamente il compilatore su cui stai lavorando e quale ottimizzazione è in grado di fare e come scrivere codice idiomatico per abilitare l'ottimizzazione
  3. Pensa ai modelli di accesso alla memoria e quanto puoi inserire nella cache (la cui dimensione esatta è nota al punto 1).
  4. Quindi se sei legato al calcolo, pensa a riorganizzare il calcolo per salvare il calcolo

Come ultima osservazione. Di solito l'unico problema che si ha con le chiamate al metodo sono i salti indiretti (metodi virtuali) che non erano previsti dal predittore di branca (sfortunatamente il salto indiretto è la causa difficile per questo). Tuttavia:

  • Java ha un JIT che in molti casi può predire il tipo di classe e quindi un target di jump in anticipo e quindi negli hotspot non dovresti avere molti problemi.
  • I compilatori C ++ spesso eseguono un'analisi del programma e almeno in alcuni casi possono predire il target in fase di compilazione.
  • In entrambi i casi, quando l'obiettivo è stato previsto, l'inlining dovrebbe funzionare. Se il compilatore non è in grado di eseguire le probabilità di inlining, non potremmo farlo anche noi.
risposta data 29.07.2013 - 19:39
fonte
0

Probabilmente la mia risposta non si espanderà troppo sulle risposte esistenti, ma ritengo che i miei due centesimi potrebbero essere utili.

Prima di tutto; sì, per la modularità, di solito si rinuncia a un certo livello di tempo di esecuzione. Scrivere tutto nel codice assembly ti darà la migliore velocità. Detto questo ...

Conosci YouTube? Probabilmente il sito con la maggiore larghezza di banda esistente o secondo su Netflix? Scrivono una grande porzione del loro codice in Python, che è un linguaggio altamente modulare non abbastanza costruito per prestazioni di alto livello.

Il fatto è che quando qualcosa va storto e gli utenti si lamentano del caricamento lento dei video, non ci sono molti scenari in cui tale lentezza verrà in definitiva attribuita alla lenta velocità di esecuzione di Python. Tuttavia, la rapida ricompilazione di Python e la sua capacità modulare di provare cose nuove senza il controllo dei tipi probabilmente permetteranno agli ingegneri di eseguire il debug di ciò che sta andando male abbastanza rapidamente ("Wow." Il nostro nuovo stagista ha scritto un ciclo che fa una nuova sotto-query SQL per OGNI risultato. ") o (" Oh, Firefox ha deprecato quel vecchio formato di intestazione della cache e hanno creato una libreria Python per configurare facilmente quella nuova ")

In questo senso, anche in termini di tempo di esecuzione, un linguaggio modulare può essere pensato come più veloce perché una volta individuati i colli di bottiglia, sarà probabilmente più facile riorganizzare il codice per farlo funzionare nel modo migliore. Così tanti ingegneri ti diranno che i colpi massacranti non erano dove pensavano di essere (e in effetti le cose che OTTIMIZZANO erano davvero necessarie, o non funzionavano nemmeno nel modo in cui si aspettavano!)

    
risposta data 29.07.2013 - 23:07
fonte
0

Sì e no. Come altri hanno notato il programma di leggibilità prima, quindi per l'efficienza. Tuttavia, esistono pratiche standard che sono sia leggibili che efficienti. La maggior parte del codice viene eseguita piuttosto di rado, e non otterrai molto vantaggio dall'ottimizzazione comunque.

Java può incorporare chiamate di funzione più piccole, quindi ci sono pochi motivi per evitare di scrivere le funzioni. Gli ottimizzatori tendono a funzionare meglio con un codice più semplice da leggere. Esistono studi che mostrano scorciatoie che teoricamente dovrebbero funzionare più velocemente, in realtà impiegano più tempo. È probabile che il compilatore JIT funzioni meglio, il codice è più piccolo e spesso i pezzi eseguiti possono essere identificati e ottimizzati. Non l'ho provato, ma mi aspetterei che una funzione di grandi dimensioni che viene chiamata relativamente raramente non venga compilata.

Questo probabilmente non si applica a Java, ma uno studio ha rilevato che le funzioni più grandi sono in realtà più lente a causa della necessità di un diverso modello di riferimento di memoria. Questo era specifico per l'hardware e l'ottimizzatore. Per le istruzioni di moduli più piccoli che hanno funzionato all'interno di una pagina di memoria sono stati utilizzati. Questi erano più veloci e più piccoli delle istruzioni richieste quando la funzione non si adattava a una pagina.

Ci sono casi in cui vale la pena ottimizzare il codice, ma in generale è necessario profilare il codice per determinare dove si trova. Trovo spesso che non sia il codice che mi aspettavo.

    
risposta data 30.07.2013 - 08:25
fonte

Leggi altre domande sui tag