Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 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.017 c
3-1132477945
AversFm
2005-11-20 12:12
2006.01.15
Реализация Master Detail для TOracleDataSet


14-1135201907
Джо
2005-12-22 00:51
2006.01.15
О свершениях и не только


2-1135538967
ZeFiR
2005-12-25 22:29
2006.01.15
Чтение после определенного символа из Edit..


3-1132322433
alpine
2005-11-18 17:00
2006.01.15
Можно ли добавить поле из третьей таблицы с помощью SQL?


3-1132313834
Карелин Артем
2005-11-18 14:37
2006.01.15
Numeric... Decimal... А отличия есть в них?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский