Duuuuża tablica w visualu

0

Mam problem, piszę program w Visualu (analiza danych czasowych, mniejsza z tym) seria danych posiada około 500 mln wartości - plik csv. Chciałbym te dane zapisać w formie tablicy double, ale niestety przy def:
double tab[500 000 000]={0};
program się zawiesza i nie działa....jak w takim razie prawidłowo zdefiniować taką tablicę?
Z góry dziękuję!!!

1

Tablica nie mieści się na stosie. Użyj dynamicznej tablicy std::vector.

std::vector<double> v(500000000, 0);
0

Program się zawiesza bo nie ma jak utworzyć takiej dużej tablicy. Double ma chyba 8 bajtów. 8 * 500 000 000 = 4000000000 bajtów = ~3,8GB (jak dobrze policzyłem). Takiego CIĄGŁEGO obszaru pamięci wymaga Twój program.
Dla takich ilości danych musisz skorzystać z jakiejś listy, która "rozrzuca" dane po pamięci. Albo przetwarzać je partiami w locie nie wczytując całości od razu.

1

@mastasso:

  1. na taką tablicę potrzebujesz 4GB pamięci w jednym bloku
  2. zmień apkę na 64bitową
  3. spróbuj coś takiego (u mnie zadziałało tylko na 64 bit):
int main()
{
	printf((sizeof(void*) == 8) ? "64bit\n" : "32bit\n");
	long long int size = 500000000;
	double* tab = new (std::nothrow) double[size];
	if (tab == NULL)
	{
		printf("chcesz za duzo\n");
		return 1;
	}
	for (long long int i = 0; i < size; i++)
	{
		tab[i] = (double)i;
	}
	delete[] tab;
    return 0;
}

osobiście podzieliłbym to na bloki max 100mb. Jak Ci to nie zadziała możesz spróbować coś w WinAPI poszukać.
Tak jak kolega wyżesz wspomniał na vector też zadziała

0
krwq napisał(a):

@mastasso:

  1. na taką tablicę potrzebujesz 4GB pamięci w jednym bloku
  2. zmień apkę na 64bitową
  3. spróbuj coś takiego (u mnie nie udaje się tego zaalokować a mam 32gb RAM):
int main()
{
	printf((sizeof(void*) == 8) ? "64bit\n" : "32bit\n");
	long long int size = 500000000;
	double* tab = new (std::nothrow) double[size];
	if (tab == NULL)
	{
		printf("chcesz za duzo\n");
		return 1;
	}
	for (long long int i = 0; i < size; i++)
	{
		tab[i] = (double)i;
	}
	delete[] tab;
    return 0;
}

dziękuję, tylko jak dodam:

for(int a=0;a<50000000;a++){tab[a]=2;}
to się wiesza:(((

sytuacja wyglada tak dane są w csv. (który ma ponad 5GB).

Program działa jak otwieram w ten sposób:


while(! plik1.eof())
{
//pobiera 5 niepotrzebnych zmiennych......
zmienna=atof(linia.c_str());
///KOD
}

tylko problem polega na tym że trwa to bardzo bardzo długu, a ja na 'zmienna' muszę wykonać wiele obliczeń więc myślę że najlepiej umieścić w tablicy? nie mam innego pomysłu......

0

odpowiedź jest prosta nie wczytuj wszystkiego na raz.
https://stackoverflow.com/questions/34751873/how-to-read-huge-file-in-c
https://www.reddit.com/r/cpp/comments/318m4n/how_to_read_a_huge_file_fast/

Co więcej robił bym obliczenia na jednym wątku/wątkach a wczytywał kolejne chunki na innym. Sego rodzaju producent-konsument

0
revcorey napisał(a):

odpowiedź jest prosta nie wczytuj wszystkiego na raz.
https://stackoverflow.com/questions/34751873/how-to-read-huge-file-in-c
https://www.reddit.com/r/cpp/comments/318m4n/how_to_read_a_huge_file_fast/

Co więcej robił bym obliczenia na jednym wątku/wątkach a wczytywał kolejne chunki na innym. Sego rodzaju producent-konsument

ale nie o to pytam, post wyżej napisałem że pobieranie danych działa, tylko jak muszę wykonać na tych danych kilka funkcji to jest problem z czasem (ja mam funkcję w formie: funkcja(double dane[],...) i chcę te 500mln upchnąć tak aby te algorytmy szybko działały.

0

A te dane jakoś od siebie zależą? Bo możesz je podzielić na kilka wątków i wykonywać algorytmy na kilku porcjach naraz.

0
mar-ek1 napisał(a):

A te dane jakoś od siebie zależą? Bo możesz je podzielić na kilka wątków i wykonywać algorytmy na kilku porcjach naraz.

no niestety nie bardzo....

0

Ile masz pamięci? Może masz problem z algorytmem. Jeśli całość się wczytuje nie powinno być problemu z odczytem czy nadpisaniem danych.

0
YooSy napisał(a):

Ile masz pamięci? Może masz problem z algorytmem. Jeśli całość się wczytuje nie powinno być problemu z odczytem czy nadpisaniem danych.

algorytmy dla mniejszych danych działają dobrze

Ja po prostu w programie robię analizę danych kilkoma algorytmami, chodzi o to aby nie tracic czasu na 20krotne wczytywanie 6 GB co trwa jakieś 40minut... tylko raz pobrać i na tym operować....może jakaś prosta lista by szybciej działała? tylko to chyba zbyt skomplikowane rozwiazanie - wolałbym tablicę

jak daje rade w takiej formie to pamięc nie jest problemem, zresztą w visualu zapełnianie pamięci trochę trwa....wiem z dośw. z symulacjami, a tytaj od razu po skompilowaniu błąd...

2

Czyli całość musisz przetworzyć kilkoma algorytmami?
To tym bardziej skłaniałbym się do wczytywania partiami, robił obliczenia i zapisywał.
Z użyciem wątków byłoby jeszcze szybciej. Jeden robi obliczenia a drugi przygotowuje następną porcję danych.
Jedno co wypadałoby sprawdzić ile trwają obliczenia i dopasować ilość wczytywanych danych aby nie czekać za długo po ukończeniu obliczeń.

0
YooSy napisał(a):

Czyli całość musisz przetworzyć kilkoma algorytmami?
To tym bardziej skłaniałbym się do wczytywania partiami, robił obliczenia i zapisywał.

tak bym się nie pytał:) takie rozbicie jest z powodu str. algorytmów (dyskretyzacja dla różnych wartości itd.) jest bardzo skomplikowane i chciałbym tego uniknąć....

0

No cóż. Użyj debugera i zlokalizuj miejsce wysypania się programu.

1
mastasso napisał(a):
revcorey napisał(a):

odpowiedź jest prosta nie wczytuj wszystkiego na raz.
https://stackoverflow.com/questions/34751873/how-to-read-huge-file-in-c
https://www.reddit.com/r/cpp/comments/318m4n/how_to_read_a_huge_file_fast/

Co więcej robił bym obliczenia na jednym wątku/wątkach a wczytywał kolejne chunki na innym. Sego rodzaju producent-konsument

ale nie o to pytam, post wyżej napisałem że pobieranie danych działa, tylko jak muszę wykonać na tych danych kilka funkcji to jest problem z czasem (ja mam funkcję w formie: funkcja(double dane[],...) i chcę te 500mln upchnąć tak aby te algorytmy szybko działały.

a ty nie zrozumiałeś odpowiedzi.

  1. Masz ogromną porcję danych musisz na nich wykonać działania
  2. Czekasz pewnie trochę czasu na samo załadowanie danych. Czy nie lepiej po prostu wczytywać po kawałku a następnie poddawać obliczeniom? Zrobisz to wielowątkowo czyli ja jednym wątku doczytujesz dane a na drugim jednocześnie liczysz na tym co masz. Kumasz już o co chodzi?
  3. Skoro masz pare funkcji które musisz wykonać to zadajesz sobie pytanie czy muszą być wykonywane jedna po drugiej czy mogą być robione wielowątkowo. Jeśli mogą być robione wielowątkowo to robisz wątki i jedziesz.
    4)zastanowić się czy można użyć GPU(opencl/cuda),
    Chcesz prostej odpowiedzi niestety takiej nie ma. Proces optymalizacji softu jest dość złożony.
    edit:

Ja po prostu w programie robię analizę danych kilkoma algorytmami, chodzi o to aby nie tracic czasu na 20krotne wczytywanie 6 GB co trwa jakieś 40minut

To czekaj twój algorytm przejeżdża po tablicy i zmienia wartości?

0

funkcja(double dane[],...)

Jeśli mają taką postać to moim daniem powinny mieć modyfikację aby tablica była const. Zmienić trzeba algorytmy tak żeby tylko czytały z tablicy. Następnie puścić je wielowątkowo. Czyli raz wczytujesz tą ogromną tablicę, następnie one sobie czytają ale wyniki modyfikacji zapisują np. na dysk.

1

To co wyżej na pewno warto wziąć pod uwagę, od siebie dodam tyle:

  • dynamiczna alokacja tak dużego bloku pamięci może się nie udać nawet jak masz jej tyle wolnej (stąd std::nothrow w kodzie krwq) - wynika to z potencjalnej fragmentacji pamięci, zwłaszcza po kilku takich alokacjach
  • csv najlepiej przetwarzać w locie na tablicę wartości double (bez buforowania w formie string)
  • jeśli masz wielokrotnie czytać te same dane, to być może warto je najpierw przekonwertować na plik binarny który powinien się dać czytać szybciej
  • wielowątkowość I/O zostawiłbym sobie na deser
0

Kilka komentarzy:

  • 40 minut na wczytanie (0.5 * 10)GB (zakładając, że nie masz zbyt wielu liczb po przecinku) to brzmi jak coś źle robisz - to powinno zająć max kilka minut - upewnij się, że nie alokujesz nic w pętli i nie masz wolnego dysku (ile zajmuje wczytanie danych bez przetwarzania? po prostu pętla z readem do jednorazowo zaalokowanego bufora)
  • zastanów się czy danych nie miałoby sensu w jakiś sposób posortować albo wcześniej przetworzyć i później wyciągać dane wyszukując binarnie czy w jakiś bardziej optymalny sposób - jeśli jest to wykonalne to powinieneś mieć wyniki b. szybko a przetworzenie zajmie jednorazowo jakiś czas (nawet jeśli będzie to kilka godzin to może być to ostatecznie lepsze)
  • rozważ użycie bazy danych - one dobrze powinny optymalizować różne operacje jeśli napiszesz sensowne zapytanie i dane dobrze przedstawisz - podejrzewam, że jak przesłałbyś schemat bazy to ktoś by Ci pomógł tutaj zaprojektować/poprawić
  • inną opcją jest podzielenie danych i policzenie na GPU - szczególnie jeśli możesz np. zamienić Twoje double na floaty to powinnieneś odczuwalnie szybciej wszystko robić (może np. da się coś heurystycznie rozwiązać zamiast dokładnie)
  • rozdziel operacje na kilka komputerów

napisz więcej detali jeśli chcesz lepszą odpowiedź

0
krwq napisał(a):

Kilka komentarzy:

  • 40 minut na wczytanie (0.5 * 10)GB (zakładając, że nie masz zbyt wielu liczb po przecinku) to brzmi jak coś źle robisz - to powinno zająć max kilka minut - upewnij się, że nie alokujesz nic w pętli i nie masz wolnego dysku (ile zajmuje wczytanie danych bez przetwarzania? po prostu pętla z readem do jednorazowo zaalokowanego bufora)
  • zastanów się czy danych nie miałoby sensu w jakiś sposób posortować albo wcześniej przetworzyć i później wyciągać dane wyszukując binarnie czy w jakiś bardziej optymalny sposób - jeśli jest to wykonalne to powinieneś mieć wyniki b. szybko a przetworzenie zajmie jednorazowo jakiś czas (nawet jeśli będzie to kilka godzin to może być to ostatecznie lepsze)
  • rozważ użycie bazy danych - one dobrze powinny optymalizować różne operacje jeśli napiszesz sensowne zapytanie i dane dobrze przedstawisz - podejrzewam, że jak przesłałbyś schemat bazy to ktoś by Ci pomógł tutaj zaprojektować/poprawić
  • inną opcją jest podzielenie danych i policzenie na GPU - szczególnie jeśli możesz np. zamienić Twoje double na floaty to powinnieneś odczuwalnie szybciej wszystko robić (może np. da się coś heurystycznie rozwiązać zamiast dokładnie)
  • rozdziel operacje na kilka komputerów

napisz więcej detali jeśli chcesz lepszą odpowiedź

Bardzo dziekuję wszystkim za uwagi,
-40 min to trochę długo ale wynika to z tego że w pliku są także inne dane i interesującą zmienną należało "wyłowic".....
na razie zrobiłem tak:
-wygenerowałem .txt tylko z tą zmienną (zajmuję już ok 2GB) i działa zacznie szybciej ok 10 min.w skrócie w taki sposób:

ifstream plik1("C:/plik.txt");
string linia;	

for(int a=0;a<10;a++)
{

while(! plik1.eof())
{		
	getline(plik1,linia);
	zmienna=strtol(linia.c_str(), NULL, 10);

	//wykonuję algorytm na "zmienna" oraz z wykorzystaniem parametru a
}
plik1.close();
cout<<"wyniki działania algorytmu dla a"<<a<<endl;

}

Czy da się to jeszcze czasowo zooptymalizować?

4

Czy da się to jeszcze czasowo zooptymalizować?

Ciężko będzie pomóc jeśli te twoje „algorytmy” są tak owiane tajemnicą, a skupiasz się na czytaniu pliku.

3

@mastasso najlepiej przekonwertuj cały kod na scanf/printf (albo fscanf jeśli na stringach się bawisz - w teorii nie powinieneś musieć używać stringów nigdzie po drodze) albo na początek walnij w kodzie na samym początku ios_base::sync_with_stdio(false); i później nie używaj w ogóle scanf/printf (z doświadczenia jednak scanf jest duuużo szybszy niż cokolwiek z iostream). Jeśli dane za często się nie zmieniają to proponuje Ci je po prostu zapisać do pliku binarnego i później bezpośrednio z niego czytać (jeśli dane używasz kilka razy to może się to opłacić, jeśli jednorazowo to raczej nie)

0

Jedna sprawa. Cza zidentyfikować wąskie gardła.
Najbardziej prymitywnie. Przed rozpoczęciem i po zakończeniu części programu wypisuj aktualną godzinę. Czyli

  1. Wypisujesz godzinę wczytujesz dane.
  2. Wczytałeś dane wypisujesz godzinę
  3. Startujesz pierwszy algorytm wypisujesz godzinę. Kończy się wypisujesz godzinę.
  4. Startujesz drugi algorytm. itd.
    Albo jedziesz narzędziami z valgrinda, czy profilerem z vs. I identyfikujesz potencjalne wąskie gardła.
0
krwq napisał(a):

@mastasso najlepiej przekonwertuj cały kod na scanf/printf (albo fscanf jeśli na stringach się bawisz - w teorii nie powinieneś musieć używać stringów nigdzie po drodze) albo na początek walnij w kodzie na samym początku ios_base::sync_with_stdio(false); i później nie używaj w ogóle scanf/printf (z doświadczenia jednak scanf jest duuużo szybszy niż cokolwiek z iostream). Jeśli dane za często się nie zmieniają to proponuje Ci je po prostu zapisać do pliku binarnego i później bezpośrednio z niego czytać (jeśli dane używasz kilka razy to może się to opłacić, jeśli jednorazowo to raczej nie)

Dzięki, ale nie bardzo rozumiem:
1)iostream to nowsza biblioteka i z tego co wiem to powstała w celu zastąpienia scanf/printf (stdio.h? czy cos w tym rodzaju) których używałem jakieś 10 lat temu.... Czy się mylę?

2)Może banalne pytanie ale rzadko pracuję na plikach (tzn. txt. mi zawsze wystarcz). Jak zapisać plik binarny? wystarczy zmienić końcówkę na *.bin? czy to przyspieszy sprawę w stosunku do txt?

  1. Racja z formatem, plik ma postać:
    ...
    1.2345
    1.2346
    1.23394
    1.2345
    ...
    jak w takim razie ominąć string i od razu do double?
0

@mastasso: nowsza częściej znaczy wygodniejsza niź szybsza - kod się nie starzeje tak jak meble.
ja bym po prostu walił fscanf z "%lf" i nic więcej - żadnego czytania liniu czy innych dodatków (zakładając, że w pliku są tylko liczby i białe znaki).

Co do plików binarnych to proponuje Ci jednak doczytać dokumentacje fopen - rozszerzenie to jest po prostu część nazwy pliku która ma jakąś przyjętą konwencje co do zawartości. Plik binarny oznacza, że jak otworzysz go w edytorze tekstowym to za wiele nie wyczytasz - po prostu patrzysz na niego jak na tablicę bajtów i musisz wiedzieć co jest w środku (napisanie kodu który wpisuje długość tablicy i liczby do pliku to powinno być kilka linii).
C++ ma dość dobrą i łatwą do czytania dokumentacje i zdecydowanie krócej zajmie Ci przeczytanie jej niż pytanie tutaj. Pliki binarne są też chyba w każdym tutorialu w C++ omówione.

0
YooSy napisał(a):

Wymuszanie wysokiej wydajności iostream

  1. To co lepiej fopen, fscan itd. czy "stuningowane" iostream?
    2)Jak bez linii przecież liczby trzeba jakoś oddzielić, jak robie
while(!feof(plik1)) 
	{

		fscanf(plik1,"%f\n",wart);
		cout<<wart<<endl;
		//strtol(linia.c_str(), NULL, 10);
		}

to się program wywala:(

Najnowsza wersja, działa, pytanie czy da się szybciej?:

ios_base::sync_with_stdio(false);
ifstream plik("C:/dane.txt",ios::binary);
string linia;	
for(int a=0;a<20;a++)
{
	while(! plik.eof())
	{
		getline(plik,linia);
		zmienna=atof(linia.c_str());
		//Algorytm(zmienna,a)
	}
}
plik.close();
  1. Poczytałem, czyli wystrczy:
    ifstream plik("C:/tick.txt",ios::binary);
    jak tak dodam to odczytuję prawidłowo dane pytanie czy szybciej?:)
0

Pytanie czy plik jest jeden, czy będzie wiele takich plików, za każdym razem innych.
I czy masz kontrolę nad procesem generowania tego pliku.

Jeżeli czytanie z pliku trwa długo to należałoby cały plik przekonwertować na format binarny i wczytywać bezpośrednio double.

0
Azarien napisał(a):

Pytanie czy plik jest jeden, czy będzie wiele takich plików, za każdym razem innych.
I czy masz kontrolę nad procesem generowania tego pliku.

Jeżeli czytanie z pliku trwa długo to należałoby cały plik przekonwertować na format binarny i wczytywać bezpośrednio double.

plik jest jeden i cały czas z niego korzystam i w nim nic nie zmieniam zawiera ok 500mln zmiennych double które analizuję za pomocą algorytmów z różnymi parametrami

0

Podpowiedzi już dostałeś: format binarny, wczytywanie/przetwarzanie blokowe, wątki.
Dopóki nie zdradzisz tych tajnych algorytmów lub tego, w jaki sposób dane są powiązane to żadnej konkretniejszej odpowiedzi nie dostaniesz.

0
tajny_agent napisał(a):

Podpowiedzi już dostałeś: format binarny, wczytywanie/przetwarzanie blokowe, wątki.
Dopóki nie zdradzisz tych tajnych algorytmów lub tego, w jaki sposób dane są powiązane to żadnej konkretniejszej odpowiedzi nie dostaniesz.

ależ algorytmy nie są tajne, to głównie testy statystyczne oraz dobór optymalnych parametrów - one nie mają nic wspólnego z moim pytaniem, moje pytanie jest ogólne i myślę że ten wątek może w przyszłości się wielu przydać mnie tylko interesuję szybki odczyt ok 500mln wartości, po uwzględnieniu podpowiedzi ostatnia wersja:

ios_base::sync_with_stdio(false);
ifstream plik("C:/dane.txt",ios::binary);
string linia;   
for(int a=0;a<20;a++)
{
    while(! plik.eof())
    {
        getline(plik,linia);
        zmienna=atof(linia.c_str());
        //Algorytm(zmienna,a)
    }
}
plik.close();

pytanie czy da się to jeszcze zooptymalizować.

1 użytkowników online, w tym zalogowanych: 0, gości: 1