Почему моя StringGrid замедляется после десятков тысяч записей?Свободный Паскаль - PullRequest
0 голосов
/ 24 ноября 2011

Я написал программу, используя 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/ в разделе «Файлы» -> «Исходный код», если вам это нужно.

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

Ted

Ответы [ 2 ]

5 голосов
/ 24 ноября 2011

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

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

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

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

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

1 голос
/ 03 февраля 2012

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

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 и т. Д. Вместо того, чтобы предоставлять компоненту управление каждой отдельной строкой, как уже упоминали другие).

...