Существует ли более быстрый путь? Я в основном должен добавить AA-ZZ к тысячам записей за один раз.
Просто список 35 объектов занимает долгое время для завершения muchless список тысячи.
procedure Tmainform.btnSeederClick(Sender: TObject);
var
ch,ch2:char;
i:integer;
slist1, slist2:TStrings;
begin
slist1:= TStringList.Create;
slist2:= TStringList.Create;
slist1.Text :=queuebox.Items.Text;
for ch := 'a' to 'z' do
begin
for ch2 := 'a' to 'z' do
begin
//
for I := 0 to slist1.Count - 1 do
begin
application.ProcessMessages; // so it doesn't freeze the application in long loops. Not 100% sure where this should be placed, if at all.
sleep(1); //Without this it doesn't process the cancel button.
if cancel then Break;
slist2.Add(slist1.Strings[i]+ch+ch2);
end;
end;
end;
insertsingle(slist2,queuebox);
freeandnil(slist1);
freeandnil(slist2);
конец;
Спасибо за любую справку
ОК. Я пытался оптимизировать ваш код. Для окончательных тестов требуется некоторые тестовые данные.
Что я сделал (он включает в себя большую часть идей из Мейсона):
Ниже приведен модифицированный код, дайте мне знать, если это работает для вас.
procedure TForm2.Button1Click(Sender: TObject);
{$define UseStringBuilder}
procedure KeepUIGoing(SourceListIndex: Integer);
begin
if SourceListIndex mod 100 = 0 then
begin
Application.ProcessMessages;
// so it doesn't freeze the application in long loops. Not 100% sure where this should be placed, if at all.
Sleep(1);
end;
end;
const
First = 'a';
Last = 'z';
type
TRange = First .. Last;
TSuffixes = array [TRange, TRange] of string;
var
OuterIndex, InnerIndex: Char;
SourceListIndex: Integer;
SourceList, TargetList: TStrings;
Suffixes: TSuffixes;
NewLine: string;
{$ifdef UseStringBuilder}
TargetStringBuilder: TStringBuilder; // could be way faster than TStringList
{$endif UseStringBuilder}
begin
for OuterIndex := First to Last do
for InnerIndex := First to Last do
Suffixes[OuterIndex, InnerIndex] := OuterIndex + InnerIndex;
SourceList := TStringList.Create;
TargetList := TStringList.Create;
{$ifdef UseStringBuilder}
TargetStringBuilder := TStringBuilder.Create();
{$endif UseStringBuilder}
try
SourceList.Text := queuebox.Items.Text;
for OuterIndex := First to Last do
begin
for InnerIndex := First to Last do
begin
for SourceListIndex := 0 to SourceList.Count - 1 do
begin
KeepUIGoing(SourceListIndex);
// if cancel then
// Break;
NewLine := SourceList.Strings[SourceListIndex] + Suffixes[OuterIndex, InnerIndex];
{$ifdef UseStringBuilder}
TargetStringBuilder.AppendLine(NewLine);
{$else}
TargetList.Add(NewLine);
{$endif UseStringBuilder}
end;
end;
end;
{$ifdef UseStringBuilder}
TargetList.Text := TargetStringBuilder.ToString();
{$endif UseStringBuilder}
// insertsingle(TargetList, queuebox);
finally
{$ifdef UseStringBuilder}
FreeAndNil(TargetStringBuilder);
{$endif UseStringBuilder}
FreeAndNil(SourceList);
FreeAndNil(TargetList);
end;
end;
- Jeroen
- JeroenВы можете построить объект и немедленно вызвать функцию для него, вы просто не можете назначить объект переменной, если вы делаете это:
MyObject().DoBar();
Практическая причина этого ограничения заключается в том, что конструктор создает объект, а вызываемая функция может также иметь возвращаемое значение, в результате чего будут получены два значения, полученные одним и тем же оператором. Тогда вам понадобится какой-то специальный синтаксис, чтобы назначить оба этих значения переменным, чего больше нигде не происходит.
И небольшое удобство, которое может быть достигнуто путем прямого вызова метода, не является большим преимуществом, что стоило бы ввести новый синтаксис для него.
-121--4585768-0 используется в качестве часового значения для обозначения нулевого или нулевого кода. аналогично тому, как указатели могут быть NULL в C. без дозора, вам потребуется дополнительный бит, чтобы проверить, был ли установлен inode в структуре или нет.
Подробнее здесь:
Все адреса блоков и inode начинаются с 1. Первым блоком на диске является блок 1. 0 используется для обозначения отсутствия блок. (Разреженные файлы могут иметь внутри них)
http://uranus.chrysocome.net/explore2fs/es2fs.htm
например, в старых файловых системах, где каталоги были представлены в виде фиксированного массива файловых записей, удаление файла приведет к установке значения inode этой записи в 0. при прохождении по каталогу любая запись с inode 0 будет игнорироваться.
-121--1644037-Существует несколько очевидных проблем с кодом.
Во-первых, вы тратите много циклов ЦП, вычисляя одни и те же значения снова и снова. Значения AA.. ZZ не будут меняться, поэтому нет необходимости строить их снова и снова. Попробуйте сделать следующее: Создайте третий список TStringList. Проходите и заполните его всеми возможными AA.. ZZ перестановок с вашим двойным циклом. Как только это закончится, выполните цикл и объедините этот список предварительно вычисленных последовательностей со значениями в slist1
. Вы должны увидеть довольно большой толчок от этого.
(Или, если время абсолютно премиально, напишите небольшую программу, которая вычислит список перестановок и сохранит его в текстовом файле, затем скомпилируйте его в приложение как строковый ресурс, который можно загрузить во время выполнения).
Во-вторых, и это, вероятно, то, что убивает вас, вы не должны иметь ProcessMessages и Sleep вызовы в самом внутреннем цикле. Сон (1);
звучит так, будто это означает «сон в течение 1 миллисекунды», но Windows не предлагает такой точности. В итоге вы получаете «сон не менее 1 миллисекунды». Он освобождает ЦП до тех пор, пока к нему не вернется Windows, которая обычно находится где-то порядка 16 миллисекунд. Таким образом, вы добавляете задержку в 16 мс (плюс до тех пор, пока ProcessMessages занимает) в очень жесткий цикл, который, вероятно, занимает всего несколько микросекунд , чтобы выполнить остальную часть своего кода.
Если вам нужно что-то подобное, чтобы поддерживать отклик пользовательского интерфейса, он должен находиться в самой внешней петле, а не во внутренней,и вам, вероятно, даже не нужно запускать его каждую итерацию. Попробуйте что-то вроде , если ch mod 100 = 0, то//sleep и обработайте сообщения здесь
. Предложение Крейга перенести эту задачу в рабочий поток также помогло бы, но только если вы знаете достаточно о потоках, чтобы сделать это правильно. Они могут быть хитрыми.
Большинство языков программирования не считают последовательность примитивной, потому что на самом деле это массив символов. Примитивные типы почти всегда имеют фиксированный размер.
Я должен сказать, что некоторые люди могут считать Последовательность «примитивным», потому что он встроен. Но это не примитивно в смысле быть базовым типом в отличие от составного типа. Поскольку последовательность представляет собой массив символов, она является составным типом.
-121--1315284-int, char, float, double и т.д. все имеют фиксированную длину в памяти. например, int имеет 4 байта, таким образом 32 бита.
но последовательность может иметь различную длину, это фактически массив символов.
-121--1315283- Чтобы остановить дополнительную обработку TStringList, необходимо окружить код slist2.BeginUpdate ()
и slist2.EndUpdate ()
.
Из моего опыта вы получите очень большое улучшение, используя меньше ProcessMessages (); Спи (1);
высказывания, как предложено в других ответах.
Попробуйте переместить его чуть ниже первого для цикла и посмотрите, какое улучшение вы получите.
Обратите внимание, что для 35 предметов, которые вы упоминаете, это действительно не стоит начать другую нить. Для нескольких тысяч предметов игры меняются. Обработка 10.000 товаров занимает 10 секунд на моем настольном компьютере.
Некоторые преимущества многопотативного:
и Окормирование некоторых подводных камней:
Вставить ниже код в нашем любимом редакторе, и вы должны быть хороши, чтобы пойти.
procedure TForm1.btnStartClick(Sender: TObject);
var
I: Integer;
begin
//***** Fill the sourcelist
FSource := TStringList.Create;
FDestination := TStringList.Create;
for I := 0 to 9999 do
FSource.Add(Format('Test%0:d', [I]));
//***** Create and fire Thread
FSeeder := TSeeder.Create(FSource, FDestination);
FSeeder.OnTerminate := DoSeederDone;
FSeeder.Resume;
end;
procedure TForm1.btnStopClick(Sender: TObject);
begin
if Assigned(FSeeder) then
FSeeder.Terminate;
end;
procedure TForm1.DoSeederDone(Sender: TObject);
var
I, step: Integer;
begin
I := 0;
step := 0;
while I < FDestination.Count do
begin
//***** Don't show every item. OutputDebugString is pretty slow.
OutputDebugString(PChar(FDestination[I]));
Inc(step);
Inc(I, step);
end;
FSource.Free;
FDestination.Free;
end;
{ TSeeder }
constructor TSeeder.Create(const source, destination: TStringList);
begin
//***** Create a suspended, automatically freed Thread object.
Assert(Assigned(source));
Assert(Assigned(destination));
Assert(destination.Count = 0);
inherited Create(True);
FreeOnTerminate := True; //***** Triggers the OnTerminate event
FSource := source;
FDestination := destination;
end;
procedure TSeeder.Execute;
var
I, J: Integer;
AString: string;
begin
FDestination.BeginUpdate;
try
FDestination.Capacity := FSource.Count * 26 * 26;
for I := 0 to Pred(FSource.Count) do
begin
AString := FSource[I];
for J := 0 to Pred(26 * 26) do
begin
FDestination.Add(AString + Char(J div 26 + $41) + Char(J mod 26 + $41));
if Terminated then Exit;
end;
end;
finally
FDestination.EndUpdate;
end;
end;
Попробуйте этот образец кода - надеюсь, что это поможет немного (Delphi 5 int./winxp) )
procedure TForm1.Button1Click(Sender: TObject);
var
i,k: Integer;
sourceList, destList: TStringList;
ch1, ch2: char;
begin
destList := TStringList.Create;
sourceList := TStringList.Create;
//some sample data but I guess your list will have 1000+
//entries?
sourceList.Add('Element1');
sourceList.Add('Element2');
sourceList.Add('Element3');
try
i := 0;
while i < (26*26) do
begin
if (i mod 100) = 0 then
Application.ProcessMessages;
ch1 := char(65 + (i div 26));
ch2 := char(65 + (i mod 26));
for k := 0 to sourceList.Count -1 do
destList.Add(Format('%s-%s%s', [sourceList.Strings[k], ch1, ch2]));
Inc(i);
end;
Memo1.Lines.AddStrings(destList);
finally
FreeAndNil(destList);
FreeAndNil(sourceList);
end;
end;
---reinhard
Я бы увидишь, сможете ли вы сделать это в одной петле согласно комментарию. Также попробуйте сделать это в потоке, чтобы вы могли устранить application.processmessages и вызовы сна, не блокируя пользовательский интерфейс.
Я знаю, что это не конкретно отвечает на ваш вопрос, но если вы заинтересованы в Delphi Algorithm's Julian Bucknall (CTO devexpress ), написал окончательные алгоритмы Delphi Algorithms
Томы Delphi: алгоритмы и структуры данных :
Вы также можете получить его EZDSL (Easy Libletry Data Structures) для Delphi 2009 и Delphi 6-2007 .
Если вы ищете чистую скорость, просто разверните код в один цикл и напишите каждую строку в качестве отдельного назначения. Вы можете написать программу, чтобы написать строки для вас автоматически, а затем скопировать и просматривать их в свой код. Это, по сути, по существу будет о самом быстром способе. Также выключите все обновления, как упомянуто выше.
procedure Tmainform.btnSeederClick(Sender: TObject);
var
ch,ch2:char;
i:integer;
slist1, slist2:TStrings;
begin
slist1:= TStringList.Create;
slist2:= TStringList.Create;
slist1.Text :=queuebox.Items.Text;
slist2.BeginUpdate()
for I := 0 to slist1.Count - 1 do
begin
application.ProcessMessages; // so it doesn't freeze the application in long loops. Not 100% sure where this should be placed, if at all.
if cancel then Break;
slist2.Add(slist1.Strings[i]+'AA');
slist2.Add(slist1.Strings[i]+'AB');
slist2.Add(slist1.Strings[i]+'AC');
...
slist2.Add(slist1.Strings[i]+'ZZ');
end;
slist2.EndUpdate()
insertsingle(slist2,queuebox);
freeandnil(slist1);
freeandnil(slist2);
end;
Если вы хотите, чтобы во время цикла обрабатывались события, например, нажатие кнопки Cancel, достаточно вызвать Application.ProcessMessages
. Если вы будете вызывать этот вызов регулярно, но не слишком регулярно, например, 50 раз в секунду, то ваше приложение будет оставаться отзывчивым на нажатие кнопки Cancel, не замедляясь слишком сильно. Application.ProcessMessages
возвращается довольно быстро, если нет сообщений для обработки.
Эта техника подходит для относительно коротких вычислений (несколько секунд), которые, как вы ожидаете, пользователь будет ждать. Для длительных вычислений больше подходит фоновый поток. Тогда ваше приложение может оставаться полностью отзывчивым, особенно если у пользователя многоядерный процессор.
Вызов Sleep
в основном потоке не позволяет вашему приложению обрабатывать события. Он позволяет другим приложениям что-то делать. Вызов Sleep
действительно переводит ваше приложение (вызывающий поток, фактически) в режим сна на запрошенное количество времени или на оставшийся временной срез потока, в зависимости от того, что больше.