2009-11-07 15 views
8

Ho un grande vettore (10^9 elementi) di caratteri e mi chiedevo quale sia il modo più veloce per scrivere tale vettore su un file. Finora ho utilizzato il seguente codice:Il modo più veloce per scrivere file vettoriale STL di grandi dimensioni utilizzando STL

vector<char> vs; 
// ... Fill vector with data 
ofstream outfile("nanocube.txt", ios::out | ios::binary); 
ostream_iterator<char> oi(outfile, '\0'); 
copy(vs.begin(), vs.end(), oi); 

Per questo codice ci vogliono circa due minuti per scrivere tutti i dati su file. La vera domanda è: "Posso renderlo più veloce usando STL e come"?

+0

C'è qualche altra elaborazione che si desidera eseguire mentre la scrittura avviene in background? In tal caso, utilizzare l'I/O sovrapposto passando vs.data() come buffer e vs.size() come numero di byte da scrivere come specificato da Charles Salvia. – Modicom

risposta

3

C'è un leggero errore concettuale con il secondo argomento del costruttore di ostream_iterator. Dovrebbe essere un puntatore NULL, se non vuoi un delimitatore (anche se, per tua fortuna, questo sarà trattato in modo implicito), o il secondo argomento dovrebbe essere omesso.

Tuttavia, questo significa che dopo aver scritto ciascun carattere, il codice deve controllare il puntatore che designa il delimitatore (che potrebbe essere alquanto inefficiente).

Penso che, se si vuole andare con iteratori, forse si potrebbe provare ostreambuf_iterator.

Altre opzioni potrebbero includere l'uso del metodo write() (se è in grado di gestire l'output così grande, o magari di stamparlo in blocchi), e forse delle funzioni di output specifiche del sistema operativo.

+1

Ho appena letto la sezione in "Effective STL" di Meyer che menziona le classi '[io] streambuf_iterator'. Perfetto per questo! – Tom

+0

Thnx per la correzione. Ho copiato incolla da qualche parte senza approfondimenti. – ljubak

+0

Ho dimenticato di dire che sto cercando di rendere le cose indipendenti dalla piattaforma, quindi OS specifico è fuori discussione, ma ancora. – ljubak

-1

Utilizzare il metodo di scrittura su di esso, è in ram dopotutto e si dispone di memoria contigua. Più veloce, mentre in cerca di flessibilità in seguito? Perdere il buffering incorporato, suggerire l'I/O sequenziale, perdere le cose nascoste di iteratore/utility, evitare streambuf quando è possibile, ma sporcarsi con boost :: asio ..

21

Con una così grande quantità di dati per essere scritto (~ 1 GB), è necessario scrivere direttamente sul flusso di output, piuttosto che utilizzare un iteratore di output. Poiché i dati di un vettore sono memorizzati in modo contiguo, questo funzionerà e dovrebbe essere molto più veloce.

ofstream outfile("nanocube.txt", ios::out | ios::binary); 
outfile.write(&vs[0], vs.size()); 
+0

Mi chiedevo perché 'outfile.write (reinterpret_cast (& (vs)), vs. dimensioni() * sizeof (T));' non funziona? – Javier

2

Poiché i dati sono contigui in memoria (come ha detto Charles), è possibile utilizzare I/O di basso livello. Su Unix o Linux, puoi scrivere in un descrittore di file. Su Windows XP, utilizzare gli handle di file. (È un po 'più complicato su XP, ma ben documentato in MSDN.)

XP è un po' divertente per il buffering. Se si scrive un blocco da 1 GB su un handle, sarà più lento rispetto a se si interrompe la scrittura in dimensioni di trasferimento più piccole (in un ciclo). Ho trovato che le scritture da 256 KB sono più efficienti. Una volta che hai scritto il ciclo, puoi giocare con questo e vedere qual è la dimensione di trasferimento più veloce.

1

OK, ho eseguito l'implementazione del metodo di scrittura con ciclo for che scrive blocchi da 256 KB (come suggerito da Rob) di dati ad ogni iterazione e il risultato è 16 secondi, quindi risolto il problema. Questa è la mia modesta implementazione quindi sentiti libero di commentare:

void writeCubeToFile(const vector<char> &vs) 
{ 
    const unsigned int blocksize = 262144; 
    unsigned long blocks = distance(vs.begin(), vs.end())/blocksize; 

    ofstream outfile("nanocube.txt", ios::out | ios::binary); 

    for(unsigned long i = 0; i <= blocks; i++) 
    { 
     unsigned long position = blocksize * i; 

     if(blocksize > distance(vs.begin() + position, vs.end())) outfile.write(&*(vs.begin() + position), distance(vs.begin() + position, vs.end())); 
     else outfile.write(&*(vs.begin() + position), blocksize); 
    } 

    outfile.write("\0", 1); 

    outfile.close(); 
} 

Thnx a tutti voi.

1

Se si dispone di un'altra struttura questo metodo è ancora valido.

Ad esempio:

typedef std::pair<int,int> STL_Edge; 
vector<STL_Edge> v; 

void write_file(const char * path){ 
    ofstream outfile(path, ios::out | ios::binary); 
    outfile.write((const char *)&v.front(), v.size()*sizeof(STL_Edge)); 
} 

void read_file(const char * path,int reserveSpaceForEntries){ 
    ifstream infile(path, ios::in | ios::binary); 
    v.resize(reserveSpaceForEntries); 
    infile.read((char *)&v.front(), v.size()*sizeof(STL_Edge)); 
} 
1

Invece di scrivere tramite il file I/metodi o, si potrebbe tentare di creare un file memory-mapped, e quindi copiare il vettore al file mappato in memoria usando memcpy.

Problemi correlati