design per un parser per gestire file molto grandi

3

Ho scritto un programma che registra i messaggi di protocollo tra un'applicazione e un dispositivo hardware che corrisponde a ciascuna richiesta di applicazione con ciascuna risposta hardware. In questo modo posso rimuovere l'hardware in seguito, connettere un'applicazione "replay" all'applicazione principale e attendere una richiesta di applicazione e rispondere con una copia corrispondente del messaggio di risposta hardware richiesto.

La mia applicazione di riproduzione salva la richiesta / risposta corrispondente in un elenco (usando C ++ std :: list).

Funziona bene su una piccola sessione di interazione. Il mio problema ora è che devo essere in grado di usare il replay per una lunga sessione. Con la mia attuale implementazione, il programma di replay utilizza infine tutta la memoria disponibile sul mio computer e si blocca.

Quindi ho bisogno di una sorta di lookahead - e non analizzare l'intera sessione in un colpo solo.

Qualcuno può dare suggerimenti su come iniziare?

    
posta user619818 15.10.2012 - 18:49
fonte

3 risposte

0

Generalmente i dati di interazione di grandi dimensioni sono serializzati su un file. Scrivi i dati in un file CSV o scrivili su un database e rileggili da esso. Registrate i dati quando superano un certo limite. Il salvataggio in questo modo manterrà la memoria in crash. Salvalo regolarmente dopo un periodo di tempo.

Cerca anche Elenco CIRCOLARE.

    
risposta data 15.10.2012 - 18:53
fonte
3

(Basta reiterare in modo che tu sappia che io so cosa stai dicendo)
Sembra che tu stia effettivamente creando una struttura in memoria delle varie richieste e risposte. Con una sessione di grandi dimensioni, questo sta creando una struttura molto grande che sta prendendo più memoria di quella che hai a disposizione.

Invece di cercare di mantenere l'intera cosa in memoria, sarebbe fattibile andare su un sistema basato su disco? Ad esempio si può andare su un Berkeley db su disco. Dispone di collegamenti C e C ++ che è possibile utilizzare per collegarsi all'applicazione corrente.

Con questo approccio, si potrebbe annullare la richiesta (l'ultima cosa che ricordo, Berkeley db ama avere chiavi semplici) e archiviare / recuperare in base all'hash. In questo modo, uno non mantiene l'intero database (o elenco) in memoria, ma piuttosto esegue ricerche indicizzate veloci su disco.

    
risposta data 15.10.2012 - 19:28
fonte
0

Innanzitutto, sappi che std :: list è una cattiva scelta per questo genere di cose, in particolare per quanto riguarda la lettura. Il motivo è che gli elementi std :: list non sono garantiti come contigui, rendono molto più lento andare da elemento a elemento a causa di errori di cache (e della mancanza di un comportamento prevedibile di accesso alla memoria).

Sarei te, la prima cosa che proverei sarebbe sostituire la std :: list con uno std :: vector, con una call da riservare prima di iniziare a spingere gli elementi indietro, per riservare molta memoria dall'inizio ed evitare allocazioni. Se usi C ++ 11, usa la funzione emplace_back () invece di push_back () per evitare definitivamente copie non necessarie dell'oggetto elemento.

Il vettore ha una memoria contigua che garantirà un accesso rapido alla lettura della sessione e sarà più efficiente in termini di memoria perché gli elementi sono sempre vicini: non c'è frammentazione della memoria.

Se ciò non è sufficiente, considera l'utilizzo di qualcosa come SQLite. Non sostituisce l'accesso in memoria, ma è possibile utilizzare la coppia di std :: array dei record come doppio buffer in cui inserire il successivo batch di record da leggere che si estrae progressivamente dal file sqlite. Per scrivere, basta fare inserti. Sia la lettura che la scrittura possono essere eseguite in un thread separato mentre l'applicazione continua a essere in esecuzione o sta elaborando i record in riproduzione.

Il motivo per cui questa configurazione potrebbe aiutare è che farebbe sì che qualsiasi dimensione della sessione non abbia impatto (o quasi) sull'applicazione che la riproduce, perché in memoria ci sarebbe solo una parte dell'intera sessione leggibile, rendendo il runtime non crescente sulla memoria, rendendo le cose veloci. In questo caso sarai limitato solo dalla velocità di accesso al disco, motivo per cui suggerisco di utilizzare una lettura (simultanea) a doppio buffer dei record. Comunque sqlite è fatto per essere molto veloce.

    
risposta data 15.10.2012 - 19:23
fonte

Leggi altre domande sui tag