TStringList studnia bez dna, aż do momentu przepełnienia jej

1

Wiemy, że TStringList potrafi wiele, ale czym więcej jest ładowane do listy tym bardziej zwiększa pamięć. Czy istnieje odczyt z pliku, aby pominąć TStringList?

Bo ListBox.Count = sl.Count;
A co z ładowaniem pliku z assignfile? Nie ma ładowania pliku do pamięci. Jedynie odczyt lini pliku. Jak połączyć to? Linie w przyroście ładowane do Countkontrolki.

0

Ten kod to niemal działanie w wątku lista uzupełniana na bieżąco. Pamięć uzupełnia się na bieżąco danymi - brak wielkich skoków pamięci. Wada powolność ładowania. Przy wielkich plikach ListBox1.Items.LoadFromFile('ex.txt') blokuje formę. A gdyby plik załadować do tablicy i z tablicy do ListBox ile by to zawierało pamięci? W samej tablicy i w tablicy razem z ListBox?

procedure TForm1.Button1Click(Sender: TObject);
var
PlikTekstowy : TextFile;
s : string;
begin
  AssignFile(PlikTekstowy, ExtractFilePath(Application.ExeName)+'ex.txt');
  Reset(PlikTekstowy);

  repeat
    readln(PlikTekstowy,s);
    ListBox1.Items.Add(s);
    application.ProcessMessages;

  until eof(PlikTekstowy);

  Closefile(PlikTekstowy);

  Showmessage('GOTOWE !!!');

end;           
0
Mariusz Bruniewski napisał(a):

Wiemy, że TStringList potrafi wiele, ale czym więcej jest ładowane do listy tym bardziej zwiększa pamięć. Czy istnieje odczyt z pliku, aby pominąć TStringList?

Istnieje i sam sobie odpowiedziałeś. Można użyć klasycznego AssignFile i czytać za pomocą ReadLn, można też skorzystać ze strumienia TFileStream, ale trzeba samemu czytać bloki danych i dzielić je na linie.

Mariusz Bruniewski napisał(a):

Ten kod to niemal działanie w wątku lista uzupełniana na bieżąco.

ProcessMessages? Serio?

Przy wielkich plikach ListBox1.Items.LoadFromFile('ex.txt') blokuje formę. A gdyby plik załadować do tablicy i z tablicy do ListBox ile by to zawierało pamięci? W samej tablicy i w tablicy razem z ListBox?

Zmarnujesz tylko czas, a wątek główny jak był blokowany, tak będzie nadal.

0

@furious programming właśnie dzięki Tobie i @kAzek kod mój działa. Na 4p. Dodałem nawet projekt plus komponent. Przez assignfile prawie 14 milionów wierszy laduje się w ciągu ponad 2h moze i więcej przy pamięci kości 6Mb. Przy moim komponencie w zaledwie 6 sekund. Chodzilo tylko o podświetlanie itemów. Assignfile to tak jakbym chciał otworzyć plik tekstowy 250Mb w notatniku Windows. Zawiesi tymczasowo Windows. Notepad.exe. Nie o to chodzi. Caly czas mam wrażenie, że u Ciebie wszystko działa. Tak u mnie wszystko działało do kilku danych. Kiedy dane zaczęły przekraczać miliony chodziło mi o czas wykonywania. I tutaj co jest większe od 1000 musi być szybkie.
Do 1000 linii to bez znaczenia. Jaką metodę wybiorę.

0

@fourius programing tu link Problem klas delphi na lazarusa Demo.rar delphi 7 może operować na plikach tekstowych do 2Gb. Sprawdzone :-) Przy 1.9Gb skladowanych danych ma problemy a 250Mb to bez problemu.

1
Mariusz Bruniewski napisał(a):

Assignfile to tak jakbym chciał otworzyć plik tekstowy 250Mb w notatniku Windows.

Nie — AssignFile niczego nie otwiera, a już na pewno nie ładuje danych do pamięci z pliku. Ta procedura jedynie kojarzy zmienną plikową z ciągiem znaków nazwy pliku i nic więcej. Plik otwiera się za pomocą Reset lub ReWrite, a dane ładuje za pomocą Read lub ReadLn.

0

@Mariusz Bruniewski:

Mariusz Bruniewski napisał(a):

@fourius programing tu link Problem klas delphi na lazarusa Demo.rar delphi 7 może operować na plikach tekstowych do 2Gb. Sprawdzone :-) Przy 1.9Gb skladowanych danych ma problemy a 250Mb to bez problemu.

Wszystko zależy od tego co chcesz osiągnąć ... ja mam napisany kod, który odczytuje plik o rozmiarze przekraczającym 13GB odczytuje z niego swojego rodzaju współrzędne x, y, z, rgb oraz kilka dodatkowych informacji, a następnie przekazuje te dane do OpenGL w celu wyrysowania swojego rodzaju mapy terenu. Całość odczytania pliku + przygotowanie sceny zajmuje czas poniżej 30 sekund na laptopie z przed kilku ładnych lat z raptem 8GB ram. Po tym czasie oczekiwania użytkownik może dowolnie operować po całym pliku bez konieczności czytania go w całości ;)

0

@Mariusz Bruniewski: a czy nie szybsze byłoby odczytywanie danych z jakiejś bazy danych, zamiast z TXT?

0
skrzat napisał(a):

@Mariusz Bruniewski: a czy nie szybsze byłoby odczytywanie danych z jakiejś bazy danych, zamiast z TXT?

Co do zasady - nie, nie byłoby. Sprawdzone.
Ale o mocno zależy, jakie dane, z jakiego pliku, z jakiej bazy danych i w jaki sposób.

W programowaniu nie ma magicznych rozwiązań, których zastosowanie sprawi że coś będzie działać "lepiej" lub "szybciej".
Zazwyczaj jedyną poprawną odpowiedzią jest - to zależy.

0

Przechowywanie tak gigantyczniej ilości danych w plikach tekstowych to słaby pomysł — marnuje się kupę czasu na konwersję tekstu na dane natywne, do tego nierzadko dochodzi parsowanie zawartości, co jeszcze bardziej zwiększa zapotrzebowanie na zasoby.

Plik amorficzny mógłby być znacznie lepszą alternatywą. Odpadnie parsowanie, odpadnie konwersja danych, a dorzucenie słownika (à la spisu treści) pozwoli odczytywać dane z dowolnego jego miejsca, natychmiast, bez względu na rozmiar pliku. Choć słownik nie będzie potrzebny, jeśli plik zawiera dane podzielone na pakiety o stałym rozmiarze — prosta matematyka wystarczy do skakania po pakietach.

Na podstawie innych wątków obstawiam, że OP ma w tym pliku wylistowane wszystkie kombinacje liczb dużego lotka (~13 milionów zestawów) i używa go tylko do odczytu. Jeśli tak faktycznie jest, to plik binarny, obsługiwany za pomocą TFileStream, będzie idealny. No ale to tylko przypuszczenia.

0

Kod z AssignFile ma pewien poważny mankament przed dodawaniem do ListBox1 musisz użyć metody BeginUpdate a na koniec EndUpdate bez tego po dodaniu elementu odmaluje się niepotrzebnie komponent

procedure TForm1.Button1Click(Sender: TObject);
var
PlikTekstowy : TextFile;
s : string;
begin
  AssignFile(PlikTekstowy, ExtractFilePath(Application.ExeName)+'ex.txt');
  Reset(PlikTekstowy);
  ListBox1.Items.BeginUpdate;
  repeat
    readln(PlikTekstowy,s);
    ListBox1.Items.Add(s);
    application.ProcessMessages;

  until eof(PlikTekstowy);
  ListBox1.Items.EndUpdate;

  Closefile(PlikTekstowy);

  Showmessage('GOTOWE !!!');

end;  
0

Ten Application.ProcessMessages ma właśnie wymuszać odmalowanie okna po każdorazowej edycji zawartości listy. W sumie to nie wiem po jaką cholerę, skoro przemalowywanie kontrolki tyle razy razy znacząco wydłuży proces ładowania danych do niej. Więc po co? Żeby mieć animację?

Zresztą ten kod wyżej robi dokładnie to samo co zwykły Items.LoadFromFile, tyle że LoadFromFile wymusza odmalowanie tylko raz (po załadowaniu danych), same dane ładuje dużymi pakietami i te pakiety dzieli na linie. W każdym razie ten kod wyżej nie ma większego sensu, a nawet żadnego sensu, skoro robi to samo co istniejąca metoda, tylko że znacznie wolniej.

0

Poruszyłem tylko jeden aspekt, o ProcessMessages pisałeś już wcześniej. Jeśli komponent jest zbyt wolny można spróbować go zamienić np. na "Virtual TreeView", pobiera on tylko dane potrzebne w danym momencie do pokazania. Do tego jednak jak już zostało to napisane trzeba mieć plik który pozwoli skoczyć do z góry znanego offsetu. Nie trzeba czekać ani marnować pamięci.

0
furious programming napisał(a):

Przechowywanie tak gigantyczniej ilości danych w plikach tekstowych to słaby pomysł — marnuje się kupę czasu na konwersję tekstu na dane natywne, do tego nierzadko dochodzi parsowanie zawartości, co jeszcze bardziej zwiększa zapotrzebowanie na zasoby.

Gdyby to była taka prosta prawda z tą konwersją i prasowaniem, to sens zastosowania i istnienia baz NoSQL (np. MongoDB) byłby wątpliwy.
A jest dokładnie odwrotnie.
Ciekawe dlaczego?
Dla wyrywnych; to jest retoryczne pytanie.

Plik amorficzny mógłby być znacznie lepszą alternatywą.

Istotnie mógłby, ale pod warunkiem, że struktur danych jest stałą i nigdy się nie zmieni.
Ja przy programowani zakładam zawsze i to samo - na pewno z czasem będzie konieczna zmiana.
A zmiana struktury danych dla takich plików jest kłopotliwa, ponieważ trzeba wykonać konwersję pliku.
To tak jakby zmiana typu danych w bazie danych zmuszała nas do jej całkowitej przebudowy.
A to wygląda na wyjątkowo paskudny pomysł.

Odpadnie parsowanie, odpadnie konwersja danych, a dorzucenie słownika (à la spisu treści) pozwoli odczytywać dane z dowolnego jego miejsca, natychmiast, bez względu na rozmiar pliku.

Jeżeli potrzeby zostaną zdefiniowane w ten sposób, to lepiej mieć pod spodem bazę danych.
I nie musi to być poważny silnik; jeśli zapisów i aktualizacji będzie sporo, to sugerowałbym SQLite.
Jeśli więcej jest odczytów i nacisk będzie postawiony bardziej na analizę danych, to DuckDB.

Choć słownik nie będzie potrzebny, jeśli plik zawiera dane podzielone na pakiety o stałym rozmiarze — prosta matematyka wystarczy do skakania po pakietach.

Na podstawie innych wątków obstawiam, że OP ma w tym pliku wylistowane wszystkie kombinacje liczb dużego lotka (~13 milionów zestawów) i używa go tylko do odczytu. Jeśli tak faktycznie jest, to plik binarny, obsługiwany za pomocą TFileStream, będzie idealny. No ale to tylko przypuszczenia.

Miałem kiedyś podobne zadanie na rekrutacji, tylko danych było 10x tyle.
Dane w pliku tekstowym.
Pierwsze co zrobiłem to wrzuciłem to do bazy danych - aby porównać wydajność przetwarzania i dowiedzieć się czy jest o co się bić.
A potem szlifowałem program do parsowania danych z TXT.
W efekcie w miarę dopracowana wersje (współbieżność, keszowanie, itd.) oferował blisko STUKROTNIE większą wydajność niż to samo w oparciu o bazę MSSQL.

I to by było na tyle, że parsowanie TXT jest tak wolne, że nie warto się tym zajmować i z tego powodu lepiej zastosować pliki amorficzne.
Nie, moim zdaniem zdecydowanie nie.

1

No ja nadal czekam (już któryś wątek z kolei) aż OP w końcu napisze co i po co trzyma w tak dużych plikach. Na razie zdołaliśmy się dowiedzieć, że to program narzędziowy do lotka, że ma ponad 1000 formularzy, że powstaje kilkanaście lat w Delphi 7 i teraz jest przenoszony do Lazarusa.

A póki nie znamy konkretów, można co najwyżej dywagować nad tym, czy lepszy tekst, czy dane binarne.

0

@furious programming a ja wielokrotnie wskazywałem, że w trybie virtualnym kontrolki TListBox nieznacznie wzrasta pamięć w stosunku do TStringList Zatem skoro mogę operować na StringListjako opcji docelowej to mogę też pokazać w nieznacznym stopniu przy utracie pamięci w kontrolce. To nie jest tak, że wszystko x2 ładuje się, czyli doTStringList i do kontrolki ListBox. W grach liczbowych jest pewna zasada. Kiedy stosujemy filtry. Tak jak ja stosuję plik się zmniejsza, ale oko też widzi pewne liczby. I tutaj właśnie o to chodzi. Nie chcę zbytnio przedstawiać filtrów i screenów z programu, gdyż do tej pory mało kto wymyślił filtry na rynku w Polsce w programach dotyczących gier liczbowych, Wszystko to TStringList cały czas na tym operuję jedynie dochodzi do wirtualnego operowania na danych w kontrolce i ich pokazywaniu! Nawet mogę przy pamięci 4Gb pokazać 95 344 200 - linii w kontrolce TListBox jeśli chodzi o grę Eurojackpot :-) Ostatnie losowanie z dnia 05-03-2021
09 23 34 40 42 01 04 TListBox radzi sobie dobrze to jedna linia a ich jest ponad 95 milionów.

0

Program jest jednostanowiskowy i nie ma mowy o tworzeniu serwera, gdyż to jedynie spowoli odczyt i zapis. Odczyt i zapis ma być w pamięci i na dysku usera.! Tego jest mnóstwo wyobraźnia jest nieograniczona! a macie filtry ! Kolego @furious programming to jedna forma a co potrafi a jest ich ponad 1000! @furious programming o czym Ty w ogóle ze mną dyskutujesz. Skoro sam przyznałeś się, że statystyka nie dla Ciebie....! Więcej okien nie mogę pokazać.

1
Mariusz Bruniewski napisał(a):

@furious programming a ja wielokrotnie wskazywałem, że w trybie virtualnym kontrolki TListBox nieznacznie wzrasta pamięć w stosunku do TStringList

No i co to ma do rzeczy? Pytałem czym są te dane, ile ich jest i w jaki sposób są zapisane w pliku.

Nie chcę zbytnio przedstawiać filtrów i screenów z programu, gdyż do tej pory mało kto wymyślił filtry na rynku w Polsce w programach dotyczących gier liczbowych

Bo to nie ma większego sensu. Choćbyś miał milion tych „filtrów” i nie wiadomo do jakiej wiedzy miał dzięki nim dostęp, to nadal, nawet w najmniejszym stopniu, nie zwiększysz swojej szansy na wygraną — w żadnej grze liczbowej. Dlatego ludzie nie poświęcają czasu na tworzenie tego typu narzędzi, bo to czysta strata czasu.


Wracając do danych — skusiłbym się na konwersję tych plików na binarne, skoro to zwykłe liczby o stałym rozmiarze pakietów. 95 milionów linii po 20 znaków na linię plus dwa znaki separatora na linię dają łącznie ponad 2GB. Zamiast 22 bajtów na pakiet można użyć 7 bajtów i rozmiar pliku zmaleje ponad trzykrotnie — do 677MB.

Ale nieważne jak te dane będą zapisane. Skoro wbudowana wirtualizacja nie działa, to można ją sobie łatwo dodać, bez względu na to czy dane są zapisane w pliku tekstowo, czy binarnie. W jednym i drugim przypadku można otworzyć plik, skoczyć w odpowiednie miejsce i przeczytać odpowiednią ilość danych.

I w sumie nadal nie wiadomo czym są te dane — 95 milionów czego? Wyników? Kombinacji?

0

O! Właśnie tu należy użyć FileMapping... haha!

Mariusz Bruniewski: błędem jest samo ładowanie takiej liczby danych do listy (ListBox?).

Generalnie można tak robić, ale wtedy robimy listę z atrybutem: LBS_NODATA.

0

Sama kontrolka TListBox nie wykazuje znacznej różnicy w pamięci sprzed wykonania kodu. Można powiedzieć, że to operacja na plikach zakłóca wszystko. Demo1 ukazuje użycie procesora i pamięci podczas zapisu do pliku. Jak działa LoadFromFile oraz SaveToFile bo mam wrażenie, że zbierają dane do ich Count w pamięci i później jest odczyt i zapis. Myślę, że zapis jak i odczyt jest spowolniony poprzez Items. To wynika, że plik jest tworzony z nagłówkiem i zawiera 0 pamięci na dysku. Później kiedy zapis nastąpi wskazuje pewną wartość na dysku.Nie udało mi się zapisać pliku przy takiej ilości danych w kontrolce powstał błąd access-violation-at-address-00000000

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