Domanda

Ho un'applicazione .NET scritta in C # (.NET 4.0). In questa applicazione, dobbiamo leggere un grande insieme di dati da un file e visualizzare il contenuto in una struttura a griglia. Quindi, per ottenere questo, ho messo una DataGridView sul modulo. Dispone di 3 colonne, tutti i dati della colonna provengono dal file. Inizialmente, il file aveva circa 600.000 record, pari a 600.000 linee nel DataGridView.

Ho subito scoperto che, DataGridView crolla con tale un grande data-set, quindi ho dovuto passare alla modalità virtuale. Per fare questo, ho letto il file completamente in 3 differenti matrici (corrispondenti a 3 colonne), e quindi viene generato l'evento CellValueNeeded, fornisco i valori corretti dagli array.

Tuttavia, ci può essere un enorme (enorme!) Numero di record in questo file, come abbiamo subito scoperto. Quando la dimensione record è molto grande, la lettura di tutti i dati in un array o un elenco <>, ecc, sembra non essere fattibile. Abbiamo rapidamente correre in errori di allocazione di memoria. (Fuori un'eccezione di memoria).

C'è rimasto bloccato lì, ma poi si rese conto, perché leggere i dati tutti in array prima, perché non leggere il file su richiesta come generato l'evento CellValueNeeded? Ecco, questo è quello che facciamo ora. Abbiamo aprire il file, ma non leggono niente, e come eventi CellValueNeeded il fuoco, in primo luogo abbiamo seek () nella posizione corretta nel file, e poi leggere i dati corrispondenti

Questo è il meglio che potevamo venire con, ma, prima di tutto questo è abbastanza lento, che rende l'applicazione lenta e non facile da usare. In secondo luogo, non possiamo evitare di pensare che ci deve essere un modo migliore per ottenere questo risultato. Ad esempio, alcuni editor binari (come HXD) sono veloce come il fulmine per qualsiasi dimensione del file, così mi piacerebbe sapere come questo può essere raggiunto.

Oh, e di aggiungere ai nostri problemi, in modalità virtuale del DataGridView, quando abbiamo fissato il RowCount al numero disponibile di righe nel file (dire 16.000.000), ci vuole un po 'per il DataGridView a anche inizializzare si. Eventuali commenti per questo 'problema' sarebbe apprezzato pure.

Grazie

È stato utile?

Soluzione

Se non è possibile montare l'intero set di dati in memoria, allora avete bisogno di un sistema di buffering. Invece di leggere solo la quantità di dati necessari per riempire il DataGridView in risposta alla CellValueNeeded, l'applicazione deve anticipare le azioni dell'utente e leggere in anticipo. Così, per esempio, quando il programma si avvia la prima volta, si dovrebbe leggere i primi 10.000 record (o forse solo 1.000 o forse 100.000 - tutto ciò che è ragionevole nel tuo caso). Poi, le richieste CellValueNeeded possono essere riempiti immediatamente dalla memoria.

Per quanto l'utente si muove attraverso la rete, il programma il più possibile i soggiorni un passo avanti rispetto all'utente. Ci potrebbero essere brevi pause se l'utente salta davanti a voi (per esempio, vuole saltare alla fine dalla parte anteriore) e si deve andare su disco al fine di soddisfare una richiesta.

Questo buffer è di solito meglio raggiunto da un thread separato, anche se la sincronizzazione a volte può essere un problema se il filo è la lettura avanti in previsione della prossima azione dell'utente, e quindi l'utente fa qualcosa di completamente inatteso come salto per l'inizio del lista.

16 milioni di record non è poi così molti record da tenere in memoria, a meno che i record sono molto grandi. Oppure, se non si dispone di molta memoria sul server. Certo, 16 milioni non è neanche lontanamente la dimensione massima di un List<T>, a meno che non T è un tipo di valore (struttura). Come molti gigabyte di dati stai parlando?

Altri suggerimenti

Bene, ecco una soluzione che sembra funzionare molto meglio:

Passo 0: Set dataGridView.RowCount ad un valore basso, diciamo 25 (o il numero effettivo che può stare in forma / schermo)

Passaggio 1:. Disabilitare la barra di scorrimento del dataGridView

Passaggio 2:. Aggiungi il tuo barra di scorrimento

Passo 3: nella vostra routine CellValueNeeded, rispondere alle e.RowIndex + scrollBar.Value

Passo 4:. Per quanto riguarda il datastore, ho aperto un flusso, e nella routine CellValueNeeded, in primo luogo fare un seek () e read () i dati richiesti

Con questi passaggi, ottengo prestazioni molto ragionevole scorrendo il DataGrid per file molto grandi (testato fino a 0,8 GB).

Quindi, in conclusione, sembra che la vera causa del rallentamento non è stato il fatto che abbiamo tenuto Seek () ING e Read () ING, ma il dataGridView vero e proprio.

Gestione righe e colonne che può essere arrotolato, sub-ammonta, utilizzato nei calcoli a più colonne, ecc presenta una serie di sfide; non proprio giusto per confrontare il problema a quelli un editore sarebbe incontrare. controlli DataGrid di terze parti sono state affrontando il problema della visualizzazione e la manipolazione di grandi serie di dati lato client fin dai tempi VB6. Non è un compito banale per ottenere prestazioni davvero scattanti utilizzando carico-on-demand o sul lato client set di dati garguantuan autonomi. Load-on-demand possono soffrire di latenza sul lato server; manipolando l'intero set di dati sul client può soffrire di limiti di memoria e CPU. Alcuni controlli di terze parti che supportano just-in-time di approvvigionamento di caricamento sia sul lato client e la logica server-side, mentre altri cercano di risolvere il problema al 100% sul lato client.

A causa .net è stratificato sulla parte superiore del sistema operativo nativo, carico di esecuzione e gestione dei dati dal disco alla memoria ha bisogno di un altro approccio. Vedere come e perché: http://www.codeproject.com/Articles/ 38069 / Memory-Management-in-NET

Per far fronte a questo problema, vorrei suggerire di non caricare tutti i dati in una sola volta. Invece caricare i dati in blocchi e visualizzare i dati più rilevanti quando necessario. Ho appena fatto un test rapido e ha scoperto che l'impostazione di una proprietà di un DataSource DataGridView è un approccio buono, ma con il grande numero di righe ci vuole anche il tempo. Quindi, utilizzare la funzione di Merge DataTable dati di carico in blocchi e mostrare all'utente i dati più rilevanti. Qui ho dimostrato un esempio che può aiutare.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top