c++ - stringhe - lettura file di testo c




Modo rapido per scrivere dati da un file std:: vector in un file di testo (4)

Ecco una soluzione leggermente diversa: salva i tuoi doppi in forma binaria.

int fd = ::open("/path/to/the/file", O_WRONLY /* whatever permission */);
::write(fd, &vector[0], vector.size() * sizeof(vector[0]));

Dato che hai detto che hai 300k doppie, che equivalgono a 300k * 8 byte = 2,4M, puoi salvarle tutte sul file del disco locale in meno di 0,1 secondi . L'unico inconveniente di questo metodo è che il file salvato non è leggibile come la rappresentazione di stringhe, ma un HexEditor può risolvere quel problema.

Se preferisci un modo più affidabile, ci sono molte librerie / strumenti di serializzazione disponibili online. Offrono maggiori vantaggi, come algoritmo di compressione flessibile indipendente dalla lingua, indipendente dalla macchina, ecc. Questi sono i due che di solito utilizzo:

Attualmente scrivo una serie di doppi da un vettore in un file di testo come questo:

std::ofstream fout;
fout.open("vector.txt");

for (l = 0; l < vector.size(); l++)
    fout << std::setprecision(10) << vector.at(l) << std::endl;

fout.close();

Ma ci vuole molto tempo per finire. C'è un modo più veloce o più efficiente per farlo? Mi piacerebbe vederlo e impararlo.


Hai due principali colli di bottiglia nel tuo programma: output e formattazione del testo.

Per aumentare le prestazioni, ti consigliamo di aumentare la quantità di dati in uscita per chiamata. Ad esempio, 1 trasferimento di output di 500 caratteri è più veloce di 500 trasferimenti di 1 carattere.

La mia raccomandazione è di formattare i dati su un buffer di grandi dimensioni, quindi bloccare scrivere il buffer.

Ecco un esempio:

char buffer[1024 * 1024];
unsigned int buffer_index = 0;
const unsigned int size = my_vector.size();
for (unsigned int i = 0; i < size; ++i)
{
  signed int characters_formatted = snprintf(&buffer[buffer_index],
                                             (1024 * 1024) - buffer_index,
                                             "%.10f", my_vector[i]);
  if (characters_formatted > 0)
  {
      buffer_index += (unsigned int) characters_formatted;
  }
}
cout.write(&buffer[0], buffer_index);

Dovresti prima provare a modificare le impostazioni di ottimizzazione nel tuo compilatore prima di giocare con il codice.


OK, sono triste che ci siano tre soluzioni che tentano di darti un pesce, ma nessuna soluzione che tenti di insegnarti come pescare.

Quando si riscontra un problema di prestazioni, la soluzione consiste nell'utilizzare un profiler e risolvere qualsiasi problema il profiler mostri.

La conversione da doppia a stringa per 300.000 doppie non richiederà 3 minuti su nessun computer spedito negli ultimi 10 anni.

La scrittura di 3 MB di dati su disco (una dimensione media di 300.000 doppie) non richiederà 3 minuti su qualsiasi computer spedito negli ultimi 10 anni.

Se si profila questo, la mia ipotesi è che scoprirai che il fout viene svuotato 300.000 volte e che il flushing è lento, perché può comportare il blocco o il semi-blocco degli I / O. Pertanto, è necessario evitare l'I / O di blocco. Il modo tipico per farlo è preparare tutto il tuo I / O su un singolo buffer (creare un flusso di stringhe, scrivere su quello) e quindi scrivere quel buffer su un file fisico in una volta sola. Questa è la soluzione descritta da hungptit, tranne per il fatto che ciò che manca sta spiegando PERCHÉ quella soluzione è una buona soluzione.

Oppure, per dirla in altro modo: ciò che il profiler ti dirà è che chiamare write () (su Linux) o WriteFile () (su Windows) è molto più lento della semplice copia di pochi byte in un buffer di memoria, perché è un utente / transizione a livello di kernel. Se std :: endl fa sì che ciò accada per ogni doppio, avrai un brutto tempo (lento). Sostituiscilo con qualcosa che rimanga nello spazio utente e metta i dati nella RAM!

Se ciò non è ancora abbastanza rapido, è possibile che la versione di precisione specifica dell'operatore << () sulle stringhe sia lenta o comporti un sovraccarico non necessario. In tal caso, potresti essere in grado di accelerare ulteriormente il codice utilizzando sprintf () o qualche altra funzione potenzialmente più veloce per generare dati nel buffer in memoria, prima di scrivere finalmente l'intero buffer in un file in una volta sola.


Puoi anche usare una forma piuttosto ordinata di emettere contenuti di qualsiasi vector nel file, con l'aiuto di iteratori e funzione di copy .

std::ofstream fout("vector.txt");
fout.precision(10);

std::copy(numbers.begin(), numbers.end(),
    std::ostream_iterator<double>(fout, "\n"));

Questa soluzione è praticamente la stessa della soluzione LogicStuff in termini di tempi di esecuzione. Ma mostra anche come stampare il contenuto solo con una singola funzione di copy che, suppongo, sembra piuttosto buona.







ofstream