2011-07-19 7 views
13

Mam wiele plików tekstowych danych w postaci liczb zmiennoprzecinkowych. Szukam najszybszego sposobu, aby je przeczytać w C++. Mogę zmienić plik na binarny, jeśli to najszybszy.odczytać pliki wejściowe, najszybszy możliwy sposób?

Byłoby wspaniale, gdybyś mógł podać mi wskazówkę lub odesłać mnie do strony internetowej z pełnym wyjaśnieniem. Nie wiem, czy istnieje jakaś biblioteka, która wykonuje pracę szybko. Nawet jeśli istnieje oprogramowanie open source, które wykonuje pracę, byłoby to pomocne.

+2

Proszę nie oznaczać pytań w języku C++ jako 'c'. To po prostu denerwujące. –

Odpowiedz

24

Posiadanie pliku binarnego jest najszybszą opcją. Nie tylko można go odczytać bezpośrednio w tablicy z surowym istream::read w jednej operacji (która jest bardzo szybka), ale można nawet zmapować plik w pamięci, jeśli system operacyjny obsługuje go; możesz używać open/ na systemach POSIX, CreateFile/CreateFileMapping/MapViewOfFile w systemie Windows lub nawet na rozwiązaniu wieloplatformowym Boost (dzięki @Cory Nelson za wskazanie go).

Szybkie & brudne przykłady, przy założeniu, że plik zawiera surowe reprezentacji niektórych float S:

"Normal" czytaj:

#include <fstream> 
#include <vector> 

// ... 

// Open the stream 
std::ifstream is("input.dat"); 
// Determine the file length 
is.seekg(0, std:ios_base::end); 
std::size_t size=is.tellg(); 
is.seekg(0, std::ios_base::beg); 
// Create a vector to store the data 
std::vector<float> v(size/sizeof(float)); 
// Load the data 
is.read((char*) &v[0], size); 
// Close the file 
is.close(); 

ze wspólną pamięcią:

#include <boost/interprocess/file_mapping.hpp> 
#include <boost/interprocess/mapped_region.hpp> 

using boost::interprocess; 

// .... 

// Create the file mapping 
file_mapping fm("input.dat", read_only); 
// Map the file in memory 
mapped_region region(fm, read_only); 
// Get the address where the file has been mapped 
float * addr = (float *)region.get_address(); 
std::size_t elements = region.get_size()/sizeof(float); 
+5

[Boost Interprocess] (http://www.boost.org/doc/libs/1_47_0/doc/html/interprocess/sharedmemorybetweenprocesses.html#interprocess.sharedmemorybetweenprocesses.mapped_file) dostarcza wieloplatformowe pliki mapowane w pamięci. –

+0

@Cory: uh, miło, nie wiedziałem, że Boost też to ma. –

+0

mapowanie pamięci będzie bardzo szybkie, jeśli plik jest już buforowany. jeśli nie, "odczyt" go pokona. –

5

Twój wąskiego gardła jest w I/O. Chcesz, aby program odczytywał tyle danych w pamięci przy najmniejszej liczbie wywołań we/wy. Na przykład odczytanie 256 numerów z jednym numerem fread jest szybsze niż 256 fread jednego numeru.

Jeśli możesz, sformatuj plik danych tak, aby odpowiadał wewnętrznej reprezentacji zmiennoprzecinkowej platformy docelowej lub przynajmniej reprezentacji programu. Zmniejsza to obciążenie związane z tłumaczeniem reprezentacji tekstowej na reprezentację wewnętrzną.

Omijanie systemu operacyjnego i używanie kontrolera DMA do odczytywania danych pliku, jeśli to możliwe. Układ DMA przenosi ciężar odczytu danych do pamięci z ramion procesora.

Kompaktuj plik danych. Plik danych chce być w jednym ciągłym zbiorze sektorów na dysku. Spowoduje to zmniejszenie czasu spędzanego na szukaniu różnych obszarów na półmiskach.

Czy programujesz kontrolę na żądanie dla zasobów dysku i procesorów. Zablokuj wszystkie inne nieważne zadania; podnieść priorytet realizacji programu.

Użyj wielu buforów, aby zatrzymać wirowanie dysku. Spora część czasu poświęcana jest oczekiwaniu na przyspieszenie i spowolnienie dysku twardego. Twój program może przetwarzać dane, podczas gdy coś innego przechowuje dane w buforze, co prowadzi do ...

Wielowątkowy. Utwórz jeden wątek, aby odczytać dane i powiadomić zadanie przetwarzania, gdy bufor nie jest pusty.

Powinny one zająć Ci trochę czasu. Wszystkie inne optymalizacje spowodują nieznaczne zwiększenie wydajności. (Takich jak bezpośredni dostęp do kontrolera dysku twardego w celu przeniesienia do jednego z buforów.)

+0

interesujące ..... – tomasz

+1

OP zawiera plik tekstowy. Przyspieszenie # 2, konwersja tego pliku tekstowego na binarny znacznie przyspieszy. Wykonaj to przez # 1, czytaj tyle, ile możesz, jednym haustem. Wszystko po tym jest sos. –

2

Kolejna uwaga poświęcona trybowi kompilacji. Próbowałem parsować plik z 1M linii. Tryb debugowania zużył 50secs, aby przeanalizować dane i dołączyć do mojego kontenera. Tryb zwolnienia zużyty co najmniej dziesięć razy szybciej, około 4sekundy. Poniższy kod służy do odczytu całego pliku przed użyciem istringstream do analizy danych jako punktów 2D (,).

vector <float> in_data; 
string raw_data; 

ifstream ifs; 
ifs.open(_file_in.c_str(), ios::binary); 
ifs.seekg(0, ios::end); 
long length = ifs.tellg(); 
ifs.seekg(0, ios::beg); 
char * buffer; 
buffer = new char[length]; 
ifs.read(buffer, length); 
raw_data = buffer; 
ifs.close(); 
delete[]buffer; 
cout << "Size: " << raw_data.length()/1024/1024.0 << "Mb" << endl; 
istringstream _sstr(raw_data); 
string _line; 

while (getline(_sstr, _line)){ 
    istringstream _ss(_line); 
    vector <float> record; 
    //maybe using boost/Tokenizer is a good idea ... 
    while (_ss) 
    { 
     string s; 
     if (!getline(_ss, s, ',')) break; 
     record.push_back(atof(s.c_str())); 
    } 
    in_data.push_back(record[0]); 
}