Почему мой StringGrid замедляется после десятков тысяч записей? Бесплатный Паскаль

Я написал программу, используя Free Pascal и Lazarus IDE. Короче говоря, он рекурсивно сканирует каталоги и «делает что-то» (хеширует) с каждым файлом, а затем выводит хеш-значения и имя файла в StringGrid, который обновляется с каждым последующим файлом.

Он отлично работает с несколькими тысячами файлов, но когда вы доходите до десятков тысяч, он действительно замедляется, обрабатывая, возможно, один файл каждые полсекунды, даже если это всего лишь небольшой файл размером в несколько Кбайт.

Основная часть ответственного кода приведена ниже. Кто-нибудь может увидеть, почему моя программа тормозит, когда количество файлов в сетке превышает десятки тысяч?

procedure TForm1.HashFile(FileIterator: TFileIterator);
var
  SizeOfFile : int64;
  NameOfFileToHash, fileHashValue, PercentageProgress : string; 
  FI : TFileIterator;                      //File Iterator class
  SG : TStringGrid;

begin
  FI := TFileIterator.Create;
  SG := TStringGrid.Create(self);
  SizeOfFile := 0;
  fileHashValue := '';

  if StopScan = FALSE then                     // If Stop button clicked, cancel scan
    begin
    NameOfFileToHash := (FileIterator.FileName);
    SizeOfFile := FileSize(NameofFileToHash);
    StatusBar1.SimpleText := 'Currently Hashing: ' + NameOfFileToHash;
    fileHashValue := CalcTheHashFile(NameOfFileToHash); // Custom function, see below

    // Now lets update the stringgrid and text fields

    // StringGrid Elements:
    // Col 0 is FileCounter. Col 1 is File Name. Col 2 is Hash
    StringGrid1.rowcount:= FileCounter+1;
    StringGrid1.Cells[0,FileCounter] := IntToStr(FileCounter);
    Stringgrid1.Cells[1,FileCounter] := NameOfFileToHash;
    Stringgrid1.Cells[2,FileCounter] := UpperCase(fileHashValue);

    // Dynamically scroll the list so the user always has the most recently hashed
    // file insight and expand the columns in lie with their content width

    StringGrid1.row := FileCounter;
    StringGrid1.col := 1;
    StringGrid1.AutoSizeColumns;

    // Progress Status Elements: Most of these vars are global vars

    NoOfFilesExamined.Caption := IntToStr(FileCounter);
    PercentageProgress := IntToStr((FileCounter * 100) DIV NoOfFilesInDir2);
    Edit1.Caption := PercentageProgress + '%';
    TotalBytesRead := TotalBytesRead + SizeOfFile;
    edtTotalBytesExamined.Caption := FormatByteSize(TotalBytesRead);

    Application.ProcessMessages;
    FileCounter := FileCounter+1;
    end;
  SG.Free;
  FI.Free;
end;

Полный исходный код доступен на моей странице SourceForge, https://sourceforge.net/projects/quickhash/ в разделе «Файлы» -> «Исходный код», если вам это нужно.

Любая помощь приветствуется

Тед


person Gizmo_the_Great    schedule 23.11.2011    source источник


Ответы (2)


Ну, как парень из Delphi, у меня выскочили две вещи. Авторазмер столбцов. Если вам повезет, он ничего не делает. Если он перемещается по всем столбцам в 10 000 строк, каждое обновление и выполняет GetTextLength, чтобы увидеть, подходит ли он, а затем перекрашивает сетку....

Таким образом, задание 1 будет состоять в том, чтобы установить некоторые размеры столбцов и прокомментировать их. Сделайте это максимум один раз в конце сканирования.

Кому захочется увидеть все 10 000+ строк одновременно?

Я думаю, что я бы передал их в файл и показал бы последнюю 1 страницу, заполненную, чтобы указать прогресс. Затем я извлекаю свой пользовательский интерфейс из файла, используя простой сценарий получения полной страницы. Зависит от того, что вы делаете с данными, но вы можете перезагрузить файл для дальнейшего анализа, выполнить сравнение изменений.

Даже если вы застряли в памяти Есть ли TList? компании THashRecord. Тогда гони свой дисплей от этого, тогда у тебя будет шанс.

person Tony Hopkinson    schedule 23.11.2011
comment
Привет Удаление авторазмера очень помогло! В моих тестах это сделало его примерно на 30% быстрее, или, другими словами, когда я добавил эту функцию, она, казалось, замедлила его на 30%, но я просто не осознавал, что это было именно так. особенность. - person Gizmo_the_Great; 12.12.2011
comment
Я нашел это тоже трудным путем. - person Tony Hopkinson; 12.12.2011

Кроме того, для большинства визуальных компонентов существует некий метод пакетного обновления, что-то вроде этого:

Try
  Grid1.BeginUpdate;  
  for Row := low(inputArray) to high(InputArray) do
    Grid1.Append(InputArray[Row].data);
Finally
  Grid1.EndUpdate;
end;

Приведенное выше явно является псевдокодом, но поищите в методах компонента что-то вроде BeginUpdate/EndUpdate. Их использование предотвратит необоснованную обработку для каждой отдельной строки. Даже если вы хотите, чтобы отображение обновлялось при заполнении, вы можете делать это каждые 10 или 100 строк вместо каждой отдельной строки.

(И, очевидно, вы можете использовать VirtualListbox и т. Д. Вместо того, чтобы давать компоненту каждую строку для управления, как уже упоминалось другими).

person Noah    schedule 03.02.2012