Member
Статус: Не в сети Регистрация: 15.04.2004 Откуда: Москва
Да что сказать. Код рабочий, только не оптимальный. да, он более
удобочитаемый, но про его производительность см. выше.
У тебя идет последовательное обращение к элементам массива, а индексный метод оправдывает себя только при произвольном доступе.
Насчет "Также необходимо применять указатели на память вместо ссылок, например взамен", то в большинстве случаев, Delphi сама умеет разъименовывать указатели.
И еще.
TBigArray = array[0..30000] of Integer; ограничивает размер массива в 30000 элементов. Точнее, размер ничем не ограничен, а вот адресация по индексу массива дальше 30000 не пойдет.
А конструкция
a: PInteger;
....
a := AllocMem(N * sizeof(Integer));
позволяет тебе получить любое кол-во элементов.
Member
Статус: Не в сети Регистрация: 14.08.2003 Откуда: Питер
Ray Adams Как индикатор хода выполнения задачи ты мне посоветовал ProgressBar, но как выяняется он жутко тормозит мне все вычисления. Привожу пример: имеется исходник
Код:
procedure TForm1.BitBtn1Click(Sender: TObject); type TDDA = array[1..362881,1..9] of shortint; var M,N: shortint; ii,iii: integer; i,j,jj,jjj: integer; S: integer; x,y: integer; z,del: shortint; seed: integer; a: ^TDDA; MM,M1: integer;
// Долбавление к массиву а столбец N!*1 справа. for i:=1 to Fac(N) do a^[i,N]:=N;
// Копирование и сортировка for jj:=1 to Fac(N) do begin z:=(jj-1) div Fac(N-1); for jjj:=1 to (N-1) do begin a^[jj,jjj]:=a^[jj-z*Fac(N-1),jjj] end; {Сортировка} {if N=M then begin Indikator.ProgressBar1.StepIt; Indikator.Update; end;} del:= (jj-1) div Fac(N-1); seed:= a[jj,N-del]; a^[jj,N-del]:= a^[jj,N]; a^[jj,N]:=seed; end; end;
// Вывод конечного массива на экран for x:=1 to Fac(M) do begin S:=0; for y:=1 to M do begin S:=S + a^[x,y]*Trunc(exp((M-y)*Ln(10))) end; //b^[x]:=S; ListBox1.Items.Strings[x-1]:= FloatToStr(s){ + ' [' + FloatToStr(x)+ ']'}; end;
//Indikator.Hide; //Indikator.Free;
FreeMem(a,(Fac(M)+1)*(M+1)*4);
sek := (GetTickCount - StartTime) div 1000; min:= sek div 60; hour:= min div 60; if sek<=60 then Label4.Caption:='Время работы = ' + FloatToStr(sek) + ' сек.' else if sek>60 then Label4.Caption:='Время работы= ' + FloatToStr(min)+'мин ' + FloatToStr(sek-60*min) + 'сек' else if hour>=1 then Label4.Caption:='Время работы= ' + FloatToStr(hour) + 'ч ' + FloatToStr(min)+'мин ' + FloatToStr(sek-60*min) + 'сек';
ListBox1.Items.EndUpdate;
end;
Время работы при N=9 составляет 2.45 мин а если убрать все прибамбасы, связанные с ProgressBar то получаю 41 сунду. Чтож это получается - Прогрессбар меня обламывает в быстродействии почти в 3.5 раза? Если N уменьшить то падение ощущается меньше - но все же?
Посоветуй что-нибудь, т.к. такая ботва меня не устраивает. Может есть другой вариант (альтернатива ПрорессБару)
или можно что-то подправить?
Добавлено спустя 1 час, 3 минуты, 4 секунды: И в догонку еще вопрос: положим я убрал Прогрессбар, и прога считает. Как только с окна проги переключаюсь на что-нибудь другое, то при возвращении к проги она как будто в подвисшем состояниии, форма - в белом цвете, но она работает и считает и как только посчитает сразу все становиться ОК! Как мне это исправить?
Member
Статус: Не в сети Регистрация: 15.04.2004 Откуда: Москва
Halfback 1. А что ты хотел? Прогрессбар - это вызовы API функций. Они никода быстрыми не были.
2. Товя задача занята расчетами, и перерисовывать форму ей некогда. А если учесть, что WM_PAINT всегда обрабатывается последним, то причина белой формы становится понятной!
Member
Статус: Не в сети Регистрация: 14.08.2003 Откуда: Питер
Avaddon
Цитата:
Товя задача занята расчетами, и перерисовывать форму ей некогда. А если учесть, что WM_PAINT всегда обрабатывается последним, то причина белой формы становится понятной!
Так ведь это понятно. Но вот как сделать, чтоб форма вырисовывалась по ходу процесса а не в завершении. Ведь взять любой из архиваторов - они тоже ведь нагружены вычислялкой но их окно никогда не становиться белым!
Цитата:
А что ты хотел? Прогрессбар - это вызовы API функций. Они никода быстрыми не были.
А можт есть компонент, заменяющий прогрессбар? Я могу, конечно, написать свой Прогрессбар при помощи Канвы или Чарта но заморачиваться неохота. А графический индикатор охота иметь на борту.
Member
Статус: Не в сети Регистрация: 15.04.2004 Откуда: Москва
Halfback Потому что архиваторы выполняют вычисления в отдельном потоке, а основной поток, получив низкий приоритет рисует формочки. Тебе рекомендую того же. Только прогресс обновлять не .Position := value, а путем проставления значения в некой переменной, а в основном потоке в Application.OnIdle проставлять значение прогреса.
Member
Статус: Не в сети Регистрация: 14.08.2003 Откуда: Питер
Avaddon Т.е. для прорисовки формы и вычислений мне нужно два потока: с высоким/средним приоритетом (вычисления) и низким приоритетом (обновление формы)? Я про это читал, вот только как реализовать - ????? Может если не в лом приведешь небольшой примерчик (желатьльно на моем примере)?
{ Класс TThread идет лесом - он тормозной, т.к. имеет оконный хэндл и процессит сообщения. Используем API-шные функции. } function CalcThreadProc(ThreadData: Pointer): DWORD; stdcall; var aForm: TResultForm; begin aForm := TResultForm(ThreadData); { Поехали, Вычисляем кол-во итераций } aForm.f_ProgressMax := Кол-во_итераций; { Вычисляем } aForm.ProgressPosition := Номер_итерации: { Закончили вычисления } aForm.f_ThreadID := 0; Application.OnIdle := nil; end;
procedure TResultForm.StartButtonClick(Sender: TObject); begin if f_ThreadID <> 0 then Exit; // Уже идет вычисление!!! if CreateThread(nil,8192,@CalcThreadProc,Pointer(Self),CREATE_SUSPENDED,f_ThreadID) = 0 then MessageBox(Handle,'Облом при создании потока для вычислений','Серьезная ошибка',MB_OK OR MB_ICONHAND) else begin SetThreadPriority(GetCurrentThread,THREAD_PRIORITY_BELOW_NORMAL); SetThreadPriority(f_ThreadID,THREAD_PRIORITY_TIME_CRITICAL); f_ProgressMax := 0; f_ProgressPosition := 0; ResumeThread(f_ThreadID); Application.OnIdle = ApplicationIdle; end; end;
procedure TResultForm.FormCreate(Sender: TObject); begin f_ThreadID := 0; end;
procedure TResultForm.ApplicationIdle(Sender: TObject); begin { Да плевать на присвоение, все равно эта зверюга не будет тормозить процесс } if f_ProgressMax = 0 then Exit; ProgressBar.Max := f_ProgressMax; ProgressBar.Position := f_ProgressPosition; end;
Member
Статус: Не в сети Регистрация: 14.08.2003 Откуда: Питер
Avaddon Что-то сложно. Во всяком случае для меня. Я вот тоже нашел один примерчик:
Код:
var pi : TProcessInformation; si : TStartupInfo;
begin ZeroMemory(@si,sizeof(si)); si.cb:=SizeOf(si); if not CreateProcess( PChar(lpApplicationName), //pointer to name of executable module PChar(lpCommandLine), // Command line. nil, // Process handle not inheritable. nil, // Thread handle not inheritable. False, // Set handle inheritance to FALSE. 0, // No creation flags. nil, // Use parent's environment block. nil, // Use parent's starting directory. si, // Pointer to STARTUPINFO structure. pi ) // Pointer to PROCESS_INFORMATION structure.
then begin Result:=false; RaiseLastWin32Error; Exit;
end;
while WaitforSingleObject(PI.hProcess,200)=WAIT_TIMEOUT do application.ProcessMessages; CloseHandle(pi.hProcess); CloseHandle(pi.hThread);
// ... здесь твой код
end;
Вроде все просто. В процедуру ЭТО СПАМ - ОТПРАВЬТЕ ЖАЛОБУ (синий квадрат) прямо копирую и казалось бы все... Но выскакивают ошибки о том, что не указаны(документированы) lpApplicationName и еще там что-то...
Может поможешь, т.к. все же твой пример какой-то замороченный. Более того задача немного упростилась: сделать так, чтобы форма в процессе вычислений не подвисала...
Member
Статус: Не в сети Регистрация: 15.04.2004 Откуда: Москва
Halfback Приведенный пример создает не поток, а процес.
И если тебя вдохновляет потом решать задачи IPC (InterProcess Communication) - то вперед.
А lpApplicationName и lpCommandLine - переменные содержащие имя запускаемого приложения и командную строка соответственно
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения