Funzioni di temporizzazione in R [chiuso]


36
  1. Vorrei misurare il tempo necessario per ripetere l'esecuzione di una funzione. L' replicate()uso di for-loop è equivalente? Per esempio:

    system.time(replicate(1000, f()));
    system.time(for(i in 1:1000){f()});

    Qual è il metodo preferito.

  2. Nell'output di system.time(), è sys+useril tempo effettivo della CPU per l'esecuzione del programma? È elapseduna buona misura della performance temporale del programma?


3
Solo per la cronaca, dato che sono chiaramente troppo tardi per cambiare il corso di questa domanda: questo è il tipo di problema che ritengo più adatto a StackOverflow.
Matt Parker,

2
@Matt Sono d'accordo sul fatto che una volta un programma sia adatto per SO. Concordo anche sul fatto che un'interpretazione letterale di questa domanda (come presa da molte delle risposte) la metterebbe fuori tema qui sul CV. Sembra che ci sia un certo interesse statistico nella progettazione di un esperimento di temporizzazione e nell'analisi dei risultati di un simile esperimento.
whuber

Risposte:


19

Per un tempismo efficace dei programmi, specialmente quando sei interessato a confrontare soluzioni alternative, hai bisogno di un controllo! Un buon modo è quello di mettere in una funzione la procedura che stai programmando. Chiamare la funzione in un ciclo di temporizzazione. Scrivi una procedura stub, essenzialmente rimuovendo tutto il codice dalla tua funzione e semplicemente ritornando da essa (ma lascia tutti gli argomenti in). Inserisci lo stub nel tuo loop di temporizzazione e ri-time. Questo misura tutte le spese generali associate ai tempi. Sottrarre il tempo di stub dal tempo della procedura per ottenere la rete: questa dovrebbe essere una misura accurata del tempo effettivo necessario.

Poiché la maggior parte dei sistemi al giorno d'oggi può essere interrotta perentoriamente, è importante eseguire diverse corse di temporizzazione per verificare la variabilità. Invece di fare una lunga corsa di secondi, esegui m corse di circa N / m secondi ciascuna. Aiuta a farlo in un doppio ciclo tutto in una volta. Non solo è più facile da gestire, ma introduce un po 'di correlazione negativa in ogni serie temporale, il che migliora effettivamente le stime.NmN/m

Usando questi principi di base della progettazione sperimentale, essenzialmente controlli eventuali differenze dovute al modo in cui distribuisci il codice (ad esempio, la differenza tra un ciclo for e replicate ()). Questo fa sì che il tuo problema scompaia.


25

Per quanto riguarda i tuoi due punti:

  1. È stilistico. Mi piace replicate()in quanto funzionale.
  2. Tendo a concentrarmi elapsed, cioè al terzo numero.

Quello che faccio spesso è

N <- someNumber
mean(replicate( N, system.time( f(...) )[3], trimmed=0.05) )

per ottenere una media ridotta del 90% di N ripetizioni di chiamata f().

(A cura, grazie a Hadley per aver catturato un thinko.)


2
Non intendi mean(replicate(N, system.time(f(...))[3]), trim = 0.05)?
Hadley,

2
Se la chiamata f () è lunga, va bene. Tuttavia, se la chiamata f () è breve, qualsiasi overhead di chiamata temporizzata probabilmente aumenterà la misurazione dell'errore. Con una singola chiamata per system.time () su molte ripetizioni di f () si arriva a dividere l'errore della chiamata fino a quando non è un valore infinitesimale (e ritorna più velocemente).
Giovanni,

@Giovanni: grazie ma non capisco bene quello che hai detto. Mi sto ancora chiedendo quale sia la migliore, ripetendo f () dentro o fuori system.time ()?
Tim

Ogni chiamata al comando system.time () ha un tempo variabile necessario per chiamare che causa una certa quantità di errore di misurazione. Questa è una piccola quantità. E se f () è una chiamata molto breve? Quindi questo errore può essere combinato con il tempo impiegato per chiamare f (). Pertanto, quando si chiama f () 1e5 volte all'interno di una singola chiamata system.time (), l'errore viene suddiviso in blocchi di 1e5. Quando chiami system.time () per ogni f () il suo impatto potrebbe essere significativo se il tempo per f () è piccolo. Naturalmente, se tutto ciò di cui hai bisogno sono i tempi relativi, non importa molto.
Giovanni,

Oh, e la seconda parte è che sarebbe più veloce chiamare system.call () una volta sola.
Giovanni,

10

Puoi anche cronometrare con i timestep restituiti da Sys.time; questo ovviamente misura il walltime, quindi il tempo di calcolo in tempo reale. Codice di esempio:

Sys.time()->start;
replicate(N,doMeasuredComputation());
print(Sys.time()-start);

3

Per quanto riguarda quale metrica di temporizzazione usare, non posso aggiungere agli altri responder.

Per quanto riguarda la funzione da usare, mi piace usare il? Benchmark dal pacchetto rbenchmark .


1

Fanno cose diverse. Tempo ciò che desideri fatto. replicate () restituisce un vettore di risultati di ogni esecuzione della funzione. Il ciclo for no. Pertanto, non sono dichiarazioni equivalenti.

Inoltre, cronometri in un certo numero di modi in cui vuoi che qualcosa venga fatto. Quindi puoi trovare il metodo più efficiente.


suggerimento mod: pubblica la seconda parte come commento alla risposta del Dirk.
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.