Форум: "Базы";
Текущий архив: 2006.01.15;
Скачать: [xml.tar.bz2];
ВнизМногопоточность и DB-компоненты Найти похожие ветки
← →
Ega23 © (2005-11-22 09:12) [0]Вопрос может показаться странным, а может даже и глупым. Дело в том, что никогда не работал с потоками.
Вопрос следующий: есть главный поток, в нём "живёт" DBGrid. Есть дополнительный поток, в нём крутится один и тот же запрос. Если DBGrid из основного потока смотрит на НД в отдельном - могут ли тут быть какие-нибудь подводные камни?
З.Ы. Напомните, что там про Архангельского было с TThread.Synchronize? :о)
← →
Savek (2005-11-22 09:25) [1]А зачем НД для Грида помещать в отдельный поток?
Synchronize используется для вызова методов VCL
← →
Ega23 © (2005-11-22 09:26) [2]
> А зачем НД для Грида помещать в отдельный поток?
Чтобы основной разгрузить.
← →
ANB © (2005-11-22 09:26) [3]
> Ega23 © (22.11.05 09:12)
Подключать грид к невыполненному запросу смысла нету. Долго ли выполняется запрос ? Если быстро - то удобнее повесить его на таймер.
← →
Ega23 © (2005-11-22 09:28) [4]
> Подключать грид к невыполненному запросу смысла нету. Долго
> ли выполняется запрос ? Если быстро - то удобнее повесить
> его на таймер.
Запрос выполняется достаточно быстро (~ 30 мс.) На таймере сейчас висит. Плохо. Всё из-за этой протокольной смотрелки тормозит.
← →
ANB © (2005-11-22 09:39) [5]Странно. На таймере не должно тормозить. Тебе по любому даже если в отдельном потоке запрос выполнять, придется синхронизировать, что запрос выполнен и его можно показывать. А если поток останавливать, когда запрос выполнен, но не разрушать и перекачивать из него данные ? Тогда, по идее, и проблем с синхронизацией быть не должно.
← →
Ega23 © (2005-11-22 09:45) [6]
> Странно. На таймере не должно тормозить. Тебе по любому
> даже если в отдельном потоке запрос выполнять, придется
> синхронизировать, что запрос выполнен и его можно показывать.
> А если поток останавливать, когда запрос выполнен, но не
> разрушать и перекачивать из него данные ? Тогда, по идее,
> и проблем с синхронизацией быть не должно.
>
Давай я попробую более подробно рассказать.
Есть некая система неких объектов. Объекты обмениваются между собой сообщениями. Эти сообщения могут быть перехвачены специальным объектом и запротоколированы в БД. Также, на некоторые сообщения, в реальном времени нужно выводить информацию на экран оператора.
Вся система работает и в одном потоке, но подтормаживает. Профилирование показало, что основные тормоза - как раз на выборке данных из протокола. Сейчас думаем, как ситуацию обойти. Хотим попробовать вынести чтение данных в отдельный поток.
← →
Juice © (2005-11-22 10:48) [7]
> Ega23 ©
Я в своих приложениях уже давно практикую такой подход (если я правильно понял). Но я деляю немного иначе, датаконтролс и датасеты я размещаю в одном потоке (главном) а сам запрос выполняю в служебном потоке. Сначала так работал с IBX/FibPLUS, теперь уже достаточное время с DBX, никаких проблем не возникало.
← →
Ega23 © (2005-11-22 10:50) [8]
> Juice © (22.11.05 10:48) [7]
>
> Я в своих приложениях уже давно практикую такой подход (если
> я правильно понял). Но я деляю немного иначе, датаконтролс
> и датасеты я размещаю в одном потоке (главном) а сам запрос
> выполняю в служебном потоке. Сначала так работал с IBX/FibPLUS,
> теперь уже достаточное время с DBX, никаких проблем не
> возникало.
>
Вопрос несколько некорректен, но всё-таки: можешь показать пример кода? :о)
← →
Juice © (2005-11-22 11:19) [9]Могу, только вам придется немного в нем разобраться - я себе для удобства написал юнит который это все делает вызовом одной функции и отображат окошко "подождите", использую не только для запросов но и прочих длительных действий.
Вот смысловая часть этого "служебного" юнита:
INTERFACE
type
// Это формочка что показывается когда идет длительная процедура
TfmWait = class(TForm)
pbProgress: TProgressBar;
lbCaption: TLabel;
tmrProgress: TTimer;
tmrShow: TTimer;
procedure tmrProgressTimer(Sender: TObject);
procedure tmrShowTimer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
// это обьявление прототипа служебной функции :
TJobParams = array of Variant;
TJobProc = procedure (out Res : PVAriant; params : TJobParams; JobThread:TThread) of object;
//Это функция которая выполняет длит.задачу без отображения окна:
function ExecInThread(const func : TJobProc; Res:PVariant; params: array of Variant) : TThread;
//Это функция которая выполняет длит.задачу показывая окно:
procedure ExecInThreadFm(const func : TJobProc; Res:PVariant; params: array of Variant; caption : string; SecToWait:integer);
IMPLEMENATATION
{ TJobThread }
procedure TJobThread.Execute;
var
JobProc:TJobProc;
begin
try
try
JobProc := func;
JobProc(Res, Params, Self);
except
on E:Exception do
begin
Res^:=-1002.1002; //Error
Application.MessageBox(PChar(E.Message), "Помилка у службовому потоці TJobThread.Execute");
end;
end;
finally
if Res^=varEmpty then Res^:=-1000.1000; //Empty Result
end;
end;
function ExecInThread(const func:TJobProc; Res:PVariant; params:array of Variant):TThread;
var
JobThread : TJobThread;
i : integer;
begin
JobThread := TJobThread.Create(true);
try
JobThread.func := func;
JobThread.res := res;
JobThread.FreeOnTerminate := true;
SetLength(JobThread.params, Length(params));
for i:=0 to High(params) do
begin
JobThread.params[i] := params[i];
end;
JobThread.Resume;
Result:=JobThread;
except
on E:Exception do
begin
if not JobThread.Suspended then JobThread.Suspend;
JobThread.Free;
E.Message := E.Message + " (помилка виникла в функції ExecInThread)";
raise;
end;
end;
end;
procedure ExecInThreadFm(const func : TJobProc; Res:PVariant; params: array of Variant; caption : string; SecToWait:integer);
var
JobThread : TThread;
fmWait : TfmWait;
begin
try
JobThread:=ExecInThread(func, Res, params);
fmWait := TfmWait.Create(Application);
fmWait.lbCaption.Caption := Caption;
fmWait.pbProgress.Max := SecToWait*10;
fmWait.tmrProgress.Enabled := true;
try
repeat
Application.ProcessMessages;
until (Res^<>varEmpty) or (fmWait.pbProgress.Position = fmWait.pbProgress.Max);
if VarIsFloat(Res^) and (Res^ = -1002.1002) then
raise Exception.Create("У службовому потоці виникла помилка !");
if fmWait.pbProgress.Position = fmWait.pbProgress.Max then
begin
TerminateThread(JobThread.Handle, 0);
raise Exception.Create("Вичерпано час !");
end;
fmWait.pbProgress.Position := fmWait.pbProgress.Max;
finally
fmWait.Close;
fmWait.Free;
end;
except
on E:Exception do
begin
E.Message := E.Message + " (помилка виникла в функції ExecInThreadFm)";
raise;
end;
end;
end;
//----------------ФОРМА ------------------------------------------------------//
procedure TfmWait.tmrProgressTimer(Sender: TObject);
begin
pbProgress.StepIt;
end;
procedure TfmWait.tmrShowTimer(Sender: TObject);
begin
Show;
tmrShow.Enabled := false;
//в tmrShow интревал установлен в 0.5 секунды, т.е. если действие выполняется быстрее чем за 0.5 сек то форма не отображатеся, если прошло 0.5. сек - форма отображается. Это чтобы она зря не мелькала на экране.
end;
Вот пример использования:
procedure TMyForm.DBConnectJob(out Res: PVAriant; params: TJobParams; JobThread:TThread);
begin
TSQLDataSet(Cardinal(params[0])).Open;
TSQLDataSet(Cardinal(params[1])).Open;
Res^ := 1; //н.д. открыты успешно
end;
procedure TMyForm.btnProcessClick(Sender: TObject);
begin
try
dsOpers.Close;
dsOpers.CommandText := "select * from ...";
dsCustomers.Close;
dsCustomers.CommandText := "select max(crole), ...";
ExecInThreadFm(DBConnectJob, @Res, [Cardinal(dsOpers), Cardinal(dsCustomers)], "Іде отримання операцій ", 15);
except
on E:Exception do
begin
E.Message := E.Message + " (Помилка відбулась в методі "+Self.Name+".btnProcessClick) ";
raise;
end;
end;
end;
← →
Ega23 © (2005-11-22 11:21) [10]Спасибо!
Дальше уже сам разберусь.
← →
Ega23 © (2005-11-22 11:36) [11]2 Juice © (22.11.05 11:19) [9]
А можно взглянуть на декларацию TJobThread ?
← →
Juice © (2005-11-22 11:41) [12]Ой, забыл.
type
TJobThread = class(TThread)
protected
procedure Execute; override;
public
func : TJobProc;
res: PVariant;
params : TJobParams;
end;
через params передаю в job-функцию параметры, через res возвращаю. В конце job-функции обязательно нужно присвоить Res^ что-то отличное от нуля.
← →
Ega23 © (2005-11-22 11:42) [13]
> через params передаю в job-функцию параметры, через res
> возвращаю. В конце job-функции обязательно нужно присвоить
> Res^ что-то отличное от нуля.
Угу, это я уже понял. Спасибо.
Страницы: 1 вся ветка
Форум: "Базы";
Текущий архив: 2006.01.15;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.015 c