2009-03-02 15 views
5

Devo serializzare un enorme albero di oggetti (7.000) nel disco. Originariamente abbiamo mantenuto questo albero in un database con Kodo, ma faremmo migliaia e migliaia di query per caricare questo albero in memoria e ci vorrebbe una buona parte del tempo disponibile per l'universo locale.Suggerimenti per la serializzazione degli oggetti Java

Ho provato la serializzazione per questo e in effetti ottengo un miglioramento delle prestazioni. Tuttavia, ho la sensazione di poter migliorare ciò scrivendo il mio codice di serializzazione personalizzato. Devo caricare questo oggetto serializzato il più velocemente possibile.

Nella mia macchina, la serializzazione/deserializzazione di questi oggetti richiede circa 15 secondi. Quando li si carica dal database, ci vogliono circa 40 secondi.

Qualche consiglio su cosa potrei fare per migliorare questa performance, tenendo conto del fatto che, poiché gli oggetti si trovano su un albero, si fanno riferimento l'un l'altro?

risposta

6

Un ottimizzazione è la personalizzazione dei descrittori di classe, in modo da memorizzare i descrittori di classe in un database diverso e nel flusso di oggetti si fa riferimento solo a essi per ID. Ciò riduce lo spazio necessario per i dati serializzati. Vedi per esempio come in un progetto le classi SerialUtil e ClassesTable lo fanno.

Creazione classi Externalizable anziché Serializable può offrire alcuni vantaggi in termini di prestazioni. Il rovescio della medaglia è che richiede un sacco di lavoro manuale.

Quindi ci sono altre librerie di serializzazione, ad esempio jserial, che possono fornire prestazioni migliori rispetto alla serializzazione predefinita di Java.Inoltre, se il grafico dell'oggetto non include cicli, può essere serializzato un po 'più veloce, perché il serializzatore non ha bisogno di tenere traccia degli oggetti che ha visto (vedere "Come funziona?" In jserial's FAQ).

+1

Ho eseguito il percorso Externalizable in passato e ho ottenuto un aumento delle prestazioni di circa il 20-23% nella serializzazione/deserializzazione di grafici di oggetti di grandi dimensioni. La quantità di lavoro richiesta per questo sarà proporzionale al numero di oggetti che devi personalizzare. – Robin

+0

Basta controllare http://code.google.com/p/fast-serialization/. Problema risolto :-) –

1

Hai provato a comprimere il flusso (GZIPOutputStream)?

+0

Ho bisogno di prestazioni migliorate per il caricamento e l'archiviazione, ma non ho specificato nella domanda e in effetti lo spazio è anche una misura di "prestazioni". –

+0

Meno spazio significa meno accesso al disco significa meno tempo –

+0

solo se il processo di serializzazione è associato al disco.non sembra essere sul mio sistema; sembra essere legato alla cpu, quindi la compressione lo rallenterà ulteriormente. –

1

Questo è come io lo farei, formano la parte superiore della mia testa

serializzazione

  1. Serialize ciascun oggetto singolarmente
  2. Assegnare ogni oggetto un unico tasto
  3. Quando un oggetto in possesso di un riferimento a un altro oggetto, inserire la chiave univoca per quell'oggetto nella posizione degli oggetti nella serializzazione. (Si usa un UUID convertito in binario)
  4. Salva ogni oggetto in un file/database/memoria utilizzando la chiave univoca

deserializzazione

  1. INIZIO Modulo di un oggetto arbitrario (di solito la radice i sospetto) unserialize e inserirlo in una mappa con la sua chiave univoca come indice e restituirlo
  2. Quando si passa a un oggetto chiave nel flusso di serializzazione, innanzitutto verificare se è già non serializzato cercando la sua chiave univoca nel mappa e se è sufficiente prenderlo da lì, se non mettere un proxy di caricamento pigro (che ripete questi due passaggi per quell'oggetto) anziché l'oggetto reale che ha gli hook per caricare l'oggetto giusto quando ne hai bisogno.

Modifica, potrebbe essere necessario utilizzare la serializzazione due passaggi e deserializzazione se si dispone di riferimenti circolari in là, complica le cose un po '- ma non più di tanto.

+0

Potrebbe funzionare, ma richiederebbe una buona parte del codice che ho –

+0

Come sarebbe un miglioramento rispetto alla serializzazione standard? Per quanto ne so, questo è già stato fatto dal meccanismo predefinito. –

+0

@saua perché puoi caricare e istanziare ogni oggetto quando necessario, invece di caricarlo tutto in una volta, puoi anche scendere a livello di byte e ottimizzare il formato di serializzazione. – thr

0

Per prestazioni, suggerisco di non utilizzare affatto la serializzazione java.io. Invece vai giù ai byte da solo.

Se si sta per java.io serializzare l'albero, potrebbe essere necessario assicurarsi che la ricorsione non diventi troppo profonda, mediante l'appiattimento (come ad esempio TreeSet) o la disposizione per serializzare prima i nodi più profondi (in modo da avere riferimenti indietro anziché chiamate nidificate readObject).

Sarei sorpreso se non ci fosse un modo in Kodo di leggere l'intero albero in uno (o pochi) passaggi.

+0

C'è un modo in Kodo per farlo, ma il problema è che dipende da come gli oggetti vengono creati nel database. Sfortunatamente il database è tale che non possiamo farlo (e non c'è modo di cambiare il modello) –

10

Non dimenticare di utilizzare la parola chiave "transitoria" per variabili di istanza che non devono essere serializzate. Questo ti dà un incremento delle prestazioni perché non stai più leggendo/scrivendo dati non necessari.

+0

Questa è una buona considerazione generale in ogni caso. Lo faccio già ma è importante menzionarlo. +1 –

4

Vorrei raccomandare di implementare personalizzati writeObject() e readObject() metodi. In questo modo sarete in grado di eliminare i nodi chidren di scrittura per ciascun nodo di un albero. Quando si utilizza la serializzazione predefinita, ciascun nodo verrà serializzato con tutti i suoi figli.

Ad esempio, writeObject() di un albero classe deve scorrere tutti i nodi di un albero e solo scrivere i dati nodi (senza nodi si) con alcuni marcatori, che identifica livello albero.

È possibile guardare LinkedList, per vedere come questi metodi sono stati implementati lì. Utilizza lo stesso approccio al fine di prevenire la scrittura prev e le voci successive per ogni singola voce.

4

Per evitare di dover scrivere il proprio codice di serializzazione, provare a provare Google Protocol Buffers. Secondo il loro sito:

I buffer di protocollo sono il meccanismo estensibile per la serializzazione di dati strutturati, neutro rispetto alla piattaforma, neutrale rispetto alla lingua di Google - think XML, ma più piccolo, più veloce e più semplice. Si definisce come si desidera strutturare i dati una sola volta, quindi è possibile utilizzare il codice sorgente generato speciale per scrivere e leggere facilmente i dati strutturati da e verso una varietà di flussi di dati e utilizzando una varietà di lingue: Java, C++ o Python

Non l'ho usato, ma ho sentito molte cose positive a riguardo. Inoltre, devo mantenere un codice di serializzazione personalizzato, e può essere un incubo da fare (per non parlare del rintracciare i bug), quindi far sì che qualcun altro lo faccia per te è sempre una buona cosa.

0

Inoltre, dare un'occhiata a XStream, una libreria per serializzare gli oggetti in XML e viceversa.

+0

L'ho già provato, per questo tipo di oggetti è anche peggio di Kodo. La serializzazione Java è di gran lunga più veloce di XStream. –

0

È possibile utilizzare Colfer per generare i bean e le prestazioni di serializzazione standard di Java avranno un incremento di 10 - 1000x. A meno che le dimensioni non superino le probabilità di un GB, sarai al di sotto di un secondo.

Problemi correlati