2009-04-13 9 views
18

Ho alcuni file di registro molto grandi e ho bisogno di analizzarli. La facilità di implementazione mi indica ovviamente Perl e regex combo (in cui sono ancora inesperto). Ma per quanto riguarda la velocità? Sarà più veloce implementarlo in C? Ogni file di registro è nell'ordine di 2 GB.Perl o C è più veloce durante l'analisi?

+0

@LFSR, sono tornato da "un parser" a "esso" poiché tale modifica modifica l'intera domanda, che credo avrebbe utilizzato un motore C RE come PCRE, non codificando manualmente un FSM. @ Alphaneo, dovresti chiarire questo per assicurarti che il tuo intento fosse chiaro. – paxdiablo

risposta

41

dubito molto C sarà più veloce di Perl a meno che non si dovesse mano compilare il RE.

Compilando a mano, intendo codificare direttamente la macchina a stati finiti (FSM) piuttosto che utilizzare il motore RE per compilarlo. Questo approccio significa che puoi ottimizzarlo per il tuo caso specifico, che spesso può essere più veloce di quello basato sul motore più generale.

Ma questo non è qualcosa che suggerirei a chiunque non abbia mai dovuto scrivere compilatori o parser senza il beneficio di lex, yacc, bison o altri strumenti simili.

I motori generalizzati, come PCRE, sono in genere potenti e abbastanza veloci (per le mie esigenze in ogni caso, e quelle esigenze sono state spesso molto).

Quando si utilizza un motore RE generale, deve essere in grado di gestire tutti i tipi di casi, sia esso scritto in C o in Perl. Quando pensi a quale sia il più veloce, devi solo confrontare quello che i motori RE sono scritti in entrambi i casi (suggerimento: il motore Perl RE è non scritto in Perl).

Sono entrambi scritti in C quindi dovresti trovare poche differenze in termini di velocità di corrispondenza.

È possono trovare differenze nel codice di supporto intorno alle ER, ma che sarà minimo, soprattutto se si tratta di un semplice// ciclo leggi partita di uscita.

+1

Implementare una macchina a stati reali ("compilare a mano l'RE") è esattamente ciò che si farebbe in C, quindi sarebbe quasi certamente più veloce. Hai anche un maggiore controllo sul comportamento del buffering dei file in C, che sarà il principale fattore determinante della velocità indipendentemente dalla lingua utilizzata. –

+0

Più veloce da eseguire ma più lento da scrivere :-). Tenderei a usare PCRE o qualcosa di simile come primo tentativo. Se le prestazioni diventano un problema, allora prenderei in considerazione la creazione di un mio FSM. – paxdiablo

+0

La scrittura di un FSM personalizzato può aiutare in una situazione come questa? Voglio dire, il tempo di CPU sarà in genere il collo di bottiglia in questa situazione o il file I/O? Supponendo, solo per semplicità, un singolo processore e un tipico disco rigido del consumatore. – intuited

4

In passato, ho trovato C più veloce, ma non nella misura in cui la scelta era una conclusione scontata.

Avete pensato di utilizzare uno strumento Log Parser generico, come Log Parser:

Log Parser è un potente versatile strumento, che fornisce interrogazione universale l'accesso ai dati basati su testo, come log file , File XML e file CSV, come e sorgenti dati chiave sul sistema operativo Windows® come il registro eventi , il Registro di sistema, il file e Active Directory®.

Questo site elenca alcuni parser di log generici.

20

Il controllo di regex Perl è fortemente ottimizzato. Qui è dove Perl brilla, non dovresti avere problemi a lavorare con un file da 2 GB in Perl e le prestazioni dovrebbero essere facilmente paragonabili alla versione C. A proposito: hai provato a cercare un parser di log già finito? Ce ne sono molti.

+0

L'analizzatore di file di registro è una novità per me, grazie, cercherò. – Alphaneo

2

Se sei esperto in Perl, usalo. Altrimenti, utilizzare AWK e SED.

testo di analisi non è quello che si vuole fare con C.

+0

A meno che tu non abbia PCRE :-) – paxdiablo

+0

+1 per riferimento AWK e SED.La mia gerarchia di lingue (vai da sinistra a destra finché non riesci a gestire bene il problema) è grep -> sed -> awk -> linguaggio compilato. –

4

Perl ovviamente ha un overhead rispetto a C.Ma questo overhead può essere trascurabile se si trascorre la maggior parte del tempo all'interno delle funzioni di Perl Regex implementate in C.

12

Se in realtà è necessario per utilizzare espressioni regolari, quindi il motore regex Perl è difficile da battere. Tuttavia, molti problemi di analisi possono essere risolti in modo più efficiente senza di essi - ad esempio, se hai solo bisogno di dividere una linea in un determinato carattere, nel qual caso C sarà probabilmente più veloce.

Se le prestazioni sono di importanza fondamentale, è necessario provare entrambe le lingue e misurare la differenza di velocità. Altrimenti, usa semplicemente quello con cui sei più a tuo agio.

8

Sto indovinando (al posto del benchmarking con i dati effettivi di Alphaneo, che non ho) che l'elaborazione I/O sarà il fattore di limite qui. E mi aspetterei un'implementazione Perl su un perl con usefaststdio abilitato per abbinare o battere un'implementazione C di base, ma per essere notevolmente più lento senza usefaststdio. (usefaststdio era attivo per impostazione predefinita in perl 5.8 e precedenti per la maggior parte delle piattaforme e disattivato per impostazione predefinita in perl 5.10.)

+0

Grazie per l'intuizione sul collo di bottiglia di IO. Importa davvero. – Alphaneo

7

La velocità è davvero un fattore? Ti interessa davvero se l'analisi viene eseguita dopo 5 o 10 minuti?

Scegli il linguaggio o lo strumento che offre le migliori funzioni di analisi e di cui sei più familiare.

+0

Al termine di un test, viene generato un log, questo file di log viene analizzato per eventuali problemi. E se c'è qualche problema, iniziamo immediatamente a lavorare sul problema. Sarà davvero utile anche se si risparmia dire qualche secondo. – Alphaneo

3

Parte di questo dipende da come l'analisi verrà integrata in un'applicazione. Se l'applicazione è il parser, allora Perl andrà bene, solo per il fatto che gestirà tutto ciò che lo circonda, ma se è integrato DIRECTLY in un'applicazione più grande, allora è del tutto possibile che tu voglia esaminare qualcosa come Lex (o Flex in questi giorni): http://en.wikipedia.org/wiki/Lex_(software) Questo strumento genera il parser per te e puoi integrare il codice C/C++ direttamente nel tuo software.

Per quanto riguarda le considerazioni sulla velocità, concordo con la maggior parte degli altri risponditori che la maturità della libreria utilizzata sarà il fattore dominante e Perl's è MOLTO maturo. Non so quanto siano mature alcune delle altre librerie (come la regex disponibile per C++ da Boost), ma visto che la maggior parte del tempo di elaborazione sarà nella libreria, i problemi linguistici sono probabilmente secondari.

Bottom line: utilizza ciò che ti è più comodo e fai tutto il lavoro possibile all'interno della libreria, poiché è quasi sempre più veloce di quello che puoi produrre da solo, in qualsiasi lingua.

21
  • Un parser perl basato su regex scritto in modo ingenuo sarà più veloce di un parser C regex scritto in modo ingenuo.
  • Un parser basato su espressioni regolari Perl ben scritto sarà molto più più veloce di un parser basato su regex C scritto in modo ingenuo.
  • Un parser C regex ben scritto sarà leggermente più veloce di un parser Perl basato su espressioni regolari ben scritto. (Sarà anche due volte più difficile da scrivere e dieci volte più difficile eseguire il debug.)
+1

Chi ha detto che stava usando un parser basato su espressioni regolari in C? Se la velocità è una preoccupazione (guidando così qualcuno a C), perché mai qualcuno dovrebbe usare l'analisi regex lenta? –

+2

(1) una regex è di gran lunga il modo più veloce di analizzare le cose ... specialmente i log. (2) un parser basato su regex c ben scritto sarà più difficile scrivere/debug di 100x rispetto a un parser perl ... perché perl regexen "Just Work (TM)" – Massa

+1

Bene, non è più veloce di un FSM progettato analizzare il tuo caso particolare. Potrebbe essere il meccanismo più veloce con qualsiasi generalità, quindi è più veloce scrivere * una regex piuttosto che scrivere un parser equivalente. In difficoltà di debug, ho ipotizzato che sarebbe stata usata una libreria di regex di tipo C, non un motore regex personalizzato. – chaos

3

Sì, puoi fare un parser molto più veloce in C se sai cosa stai facendo.

Tuttavia, per la stragrande maggioranza delle persone una cosa più intelligente di cui preoccuparsi sarebbe la facilità di implementazione e la manutenzione del codice. Un parser veloce che non riesci a far funzionare correttamente non fa bene a nessuno.

1

Se si analizzano i registri nel formato di registro comune di Apache, visitors, che è scritto in C, verrà battuto qualsiasi analizzatore di log perl paragonabile di almeno un fattore 2.

Quindi trovare i parser esistenti e confrontarli se il formato del registro è comune.

Un parser di log correttamente scritto in C sarà sempre significativamente più veloce di un parser di log correttamente scritto in Perl, basato sulle mie esperienze passate.

17

Se siete altrettanto abile in C e Perl, la risposta è semplice:

  1. scriverlo in Perl.
  2. Se è troppo lento, profilarlo e ripararlo.
  3. Se è ancora troppo lento, e il problema è eccessivo CPU o l'utilizzo della RAM, non crei in C.

In generale, direi che questo vale se non si è una sorta di C godlet che possono manipolare abilmente i fondamenti della realtà attraverso manipolazioni puerili di puntatori e tipografie.

Seriamente, l'implementazione di regex in perl è molto veloce, flessibile e ben testata. Qualsiasi codice che scrivi può essere veloce e flessibile, ma non può mai essere così accuratamente testato.

Dal momento che siete nuovi in ​​Perl ed espressioni regolari, è importante ricordare che ci sono resources che possono provide voi con excellent help se ne avete bisogno. Ci sono anche alcuni nice tutorials nel fine manual.

Qualunque cosa tu faccia, non farlo:

for my $line (<$log>) { 
    # parse line here. 
} 

Potrai leggere l'intero file di log nella memoria e ci vorrà per sempre come i vostri swap e swap di sistema (e possibilmente crash).

Utilizzare invece un ciclo while:

while (defined(my $line = <$log>)) { 
    # parse line here. 
} 
+2

Non sono un esperto Perl. Perché esattamente per lo snippet sta leggendo l'intero file? Ha qualcosa a che fare con il fatto che per sapere in anticipo quante volte girare, ma mentre controlla ogni volta? –

+0

@Ignas, ho perso il tuo commento, quindi potresti non vederlo mai. Nel caso in cui trovi la strada del ritorno: 'for' reads valuta il contenuto dei parens nel contesto dell'elenco. '<>' nel contesto della lista cattura l'intero file. 'while' valuta il codice in parens in contesto scalare. Nel contesto scalare, '<>' legge una riga alla volta. – daotoad

+0

il ciclo while si fermerà alla prima riga vuota, o qualsiasi altra cosa che perl consideri falsa. utilizzare while (definito (my $ line = <$log>)). –

1

Se avete intenzione di essere applicando la stessa espressione regolare per ogni linea, non dimenticate che è possibile ottimizzare notevolmente l'esecuzione aggiungendo il flag/o al il modello, cioè

if (/ [a-zA-Z] +/o)

questo modo l'espressione da elaborare internamente sola volta e per tale risultato essere successivamente riutilizzato, anziché su ogni ciclo successivo iterazione.

Armato di questo miglioramento, sarei molto sorpreso se il parser del Perl non fosse andato a capo di qualsiasi implementazione C che sarebbe stato possibile realizzare in un lasso di tempo realistico.

+2

Questo non è vero (altro). Per molto tempo, l'opzione/o per le espressioni regolari è stata per lo più superflua. Ha sempre e solo un effetto se si interpolano le variabili nell'espressione regolare. Altrimenti, verrà compilato solo una volta. Vedi "perldoc perlre". – tsee

+0

Sono d'accordo. Sembrava che l'autore volesse interpolare le variabili. –

1

Se si desidera leggere 2 GB di perl, è preferibile utilizzare sysread (con dimensioni di blocco di dimensioni grandi, ad esempio 256k o 512k). PerlIO utilizza una dimensione di blocco troppo piccola - 4k, è inefficiente. Vedi PerlMonks per maggiori informazioni sulla dimensione del blocco PerlIO.