Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2011.02.27;
Скачать: [xml.tar.bz2];

Вниз

Запрос в потоке. Правильно пишу?   Найти похожие ветки 

 
12 ©   (2010-11-30 15:48) [0]

     
 TQ: ThQuery;
после прочтения Многопоточность - как это делается в Дельфи
решил применить к жизни.
Пишу
...
     TQ := ThQuery.Create(True);
     TQ.FreeOnTerminate := True;
     TQ.Q := AQuery;
     TQ.Resume;
....

где,
type
 ThQuery = class(TThread)
 private  
   FQ: TOraQuery;  
   function GetQ: TOraQuery;
   procedure SetQ(const Value: TOraQuery);
 protected
   procedure Execute; override;
 public
   property Q: TOraQuery read GetQ write SetQ;
 end;

implementation

procedure ThQuery.Execute;
begin
 Q.Open;
end;
function ThQuery.GetQ: TOraQuery;
begin
 Result := FQ;
end;
procedure ThQuery.SetQ(const Value: TOraQuery);
begin
 FQ := Value;
end;


 
12 ©   (2010-11-30 15:52) [1]

к чему - что-то не вижу разницы, притормаживает все равно.
Тесты на пару миллионах записях, fetchall = true


 
Engine ©   (2010-11-30 15:53) [2]

Неправильно, нет синхронизации между Q и FQ


 
Ega23 ©   (2010-11-30 15:54) [3]

А теперь навесь на данный экземпляр TOraQuery несколько обработчиков, прицепи DataSource и DBGrid.
И посмотри на результат.


 
12 ©   (2010-11-30 15:57) [4]

да?
что-то не уверен,

класс потока переписал так, остальное оставил

type
ThQuery = class(TThread)
protected
  procedure Execute; override;
public
  Q: TOraQuery;
end;

implementation

procedure ThQuery.Execute;
begin
Q.Open;
end


 
12 ©   (2010-11-30 15:59) [5]


> Ega23 ©   (30.11.10 15:54) [3]

не, наверное не так выразился.
По-идее, должно быть так: Нажал выполнить запрос - а форму в это время можно таскать, ресазить, она должна отвечать, словом.

Не отвечает все равно, с пол-секунды где-то


 
engine ©   (2010-11-30 16:01) [6]

хотя бы так, надо:

type
ThQuery = class(TThread)
private  
  FQ: TOraQuery;  
  CS: TCriticalSection;
  function GetQ: TOraQuery;
  procedure SetQ(const Value: TOraQuery);
protected
  procedure Execute; override;
public
  property Q: TOraQuery read GetQ write SetQ;
end;

implementation

procedure ThQuery.Execute;
begin
Q.Open;
end;
function ThQuery.GetQ: TOraQuery;
begin
EnterCriticalSection(CS);
Result := FQ;
LeaveCriticalsSection(CS);  
end;
procedure ThQuery.SetQ(const Value: TOraQuery);
begin
EnterCriticalSection(CS);
FQ := Value;
LeaveCriticalsSection(CS);
end;


ну и добавить InitializeCriticalSection/DeleteCriticalSection;


 
Игорь Шевченко ©   (2010-11-30 16:20) [7]


>  TQ: ThQuery;
> после прочтения Многопоточность - как это делается в Дельфи
> решил применить к жизни.
> Пишу


нафиг тебе это ?


 
Ega23 ©   (2010-11-30 16:22) [8]


> хотя бы так, надо:


И чего это даст???


 
engine ©   (2010-11-30 16:27) [9]

на сколько я понимаю, то в данном случае это защитит от одновременного обращения к полю FQ из основного и доп.потока, или я не прав? Поправьте тогда, самому интересна эта тема.


 
Ega23 ©   (2010-11-30 16:27) [10]

По-хорошему, надо делать как-то так:
1. Передать в тред ConnectionString
2. Передать в тред текст запроса
3. Создать соединение с БД, создать DataSet
4. Выполнить, дождаться конца
5. Отсигналить в основной тред, что данные зафетчены
6. Перегнать данные в основной тред (ну или передать сам НД, хотя я бы не стал)
7. Убиться.

При многих тредах имеет смысл организовать пул соединений. Хотя это от архитектуры зависит.


 
Ega23 ©   (2010-11-30 16:30) [11]


> на сколько я понимаю, то в данном случае это защитит от
> одновременного обращения к полю FQ из основного и доп.потока,
>  или я не прав? Поправьте тогда, самому интересна эта тема.


Да. Защитит. На момент операции присваивания. Но никак не защитит на момент выполнения самого треда.

Ну и в качестве ремарки: если есть EnterCriticalSection, то Leave - исключительно через try..finally. Иначе впоследствии намучаешься DeadLock-и ловить.


 
Ega23 ©   (2010-11-30 16:36) [12]

Тут подумал. Вообще не защитит. Ни от чего. Вообще бессмысленно.


 
engine ©   (2010-11-30 16:36) [13]


> Но никак не защитит на момент выполнения самого треда.
>

Точно, каюсь, был невнимателен. А за ремарку спасибо, об этом я не знал. Пошел править.


 
engine ©   (2010-11-30 16:38) [14]

а если так:
 EnterCriticalSection(CS)
 try
   FQ.Open;
 finally
   LeaveCriticalSection(CS);
 end;


 
Юрий Зотов ©   (2010-11-30 16:39) [15]


> Ega23 ©   (30.11.10 16:22) [8]

Только то, что во время выполнения длительного запроса у юзера не возникнет ощущения, что программа зависла.


 
engine ©   (2010-11-30 16:39) [16]

Или бессмысленно, т.к. работаем с ссылкой на объект, а не с самим объектом?


 
Юрий Зотов ©   (2010-11-30 16:41) [17]


> engine ©   (30.11.10 16:39) [16]

В Delphi (и не только) любой объект - это ссылка.


 
Ega23 ©   (2010-11-30 16:41) [18]


> Или бессмысленно, т.к. работаем с ссылкой на объект, а не
> с самим объектом?


Тут дело в другом. Нужно чтобы и стой стороны, ну, со стороны основного треда, доступ к FQ тоже через эту же крит-секцию был организован.


 
engine ©   (2010-11-30 16:43) [19]

тогда [14] должно быть правильно


 
Ega23 ©   (2010-11-30 16:44) [20]


> engine ©   (30.11.10 16:38) [14]
>
> а если так:


А что это даст? Это будет означать, что данный тред встал в крит-секцию и выполняет FQ.Open
при этом, если ссылка на этот FQ есть у кого-то другого, ничего не мешает этому "другому" сделать FQ.Free.
Ибо этот "другой" ничего про твою крит-секцию не знает и слюной на неё плевать хотел.


 
engine ©   (2010-11-30 16:46) [21]

как сделает? Он же через property к FQ обращается, а там защищено


 
Ega23 ©   (2010-11-30 16:53) [22]


> как сделает? Он же через property к FQ обращается, а там
> защищено


Да щаз.


type
ThQuery = class(TThread)
private  
  FQ: TOraQuery;  
  function GetQ: TOraQuery;
  procedure SetQ(const Value: TOraQuery);
protected
  procedure Execute; override;
public
  property Q: TOraQuery read GetQ write SetQ;
end;


В проперть-то его кто положил? Оно от сырости там завелось?

самый простой пример:
1. я создал экземпляр TOraQuery (в основном треде). Назовём Q1: TOraQuery.
2. я создал экземпляр ThQuery (в основном треде). Назовём Th1: ThQuery
3. я присвоил Th1.Q := Q1;
4. Отправил Th1.Resume
5. Th1 выполняется полчаса, например
6. через минуту я взял и вызвал Q1.Free.

Заметь, не Th1.Q.Free, а именно Q1.Free


 
engine ©   (2010-11-30 17:00) [23]

Согласен, изначально реализация была кривой. Хорошо, что у меня объекты, с которыми работает поток, создаются внутри потока.
Спасибо, за подробное объяснение.


 
12 ©   (2010-11-30 17:17) [24]

ща, поробую
и сам уже на листке порисовал-порисовал   -  надо, наверное, в потоке кверик создать
передавать пользователю только хотелось бы изящно - ссылку на область, которую будет трактовать как надо


 
Ega23 ©   (2010-11-30 17:23) [25]

Про Owner e Qwery не забывай. Либо разрушай самостоятельно.
Хотя стрёмный это путь. Не нравится чем-то. Чем - не могу сказать.


> передавать пользователю только хотелось бы изящно


SendMessage главному окну, LParam = Integer(Query)

соответственно, в главном окне Query = TOraQuery(Pointer(LParam))


 
12 ©   (2010-11-30 17:40) [26]


> SendMessage главному окну, LParam = Integer(Query)
> соответственно, в главном окне Query = TOraQuery(Pointer(LParam))

Это понятно, это давно использую
Но, тут в потоке. Придет ссылка - а поток разрушен, вдруг?
Надо гарантировать, что не разрушится
Ща, еще порисую..
Спасибо, Олег.

Просто первый раз серьезно решил заняться. На уровне сдать лабу - сдавал, но не пригодилось никогда еще :)

Кстати,
2 ИШ


> нафиг тебе это ?

Программирование - то? :)
Да как сказать..

Вот Вы большой и умный и Мастер даже..
А все норовите обидеть да задеть. Мне то пофиг, меня так обижали - ой-ёй

И получается, что просто Вас читать даже не хочется - ну чего нового Вы расскажете - ничего. Только сделаете очередную попытку оскорбить

А от Мастера ожидается как-бы посыл хоть и на 3 буквы (я про www, не подумайте :)) но чтоб мысли родились в голове.
от посыла то, от этого, от мастерского :)

Ну вот как-то так.


 
Engine ©   (2010-11-30 17:47) [27]

Может тогда не использовать FreeOnTerminate :=true? Разрушать только тогда, когда уж точно не нужен больше.


 
Ega23 ©   (2010-11-30 17:49) [28]


> Но, тут в потоке. Придет ссылка - а поток разрушен, вдруг?
>
> Надо гарантировать, что не разрушится


Блин. Ты свой Query в потоке создал, но не разрушил. Разрушать будет главный поток.
Дальше, из потока ты сделал SendMessage. В параметре передал ссылку на созданный Query. Пока обработчик SendMessage не отработает - поток будет ждать. Соответственно, там ссылку из параметра сохранил и сделал все телодвижения.
Поток дождался и убился. При этом деструктор Query не вызывает.


 
Ega23 ©   (2010-11-30 17:53) [29]

Но мне эта схема всё равно не нравится. Используй TClientDataSet, что-ли...


 
engine ©   (2010-11-30 18:07) [30]

Вот еще интересный вариант:
http://www.delphikingdom.ru/asp/viewitem.asp?catalogid=1355

Интересно, что о нем думают мастера?


 
Игорь Шевченко ©   (2010-11-30 18:22) [31]


> Программирование - то? :)


не, дваркование запроса в отдельном потоке влэндишым способом.


> А все норовите обидеть да задеть.


А теперь подумай - а нафиг мне это ?


 
MsGuns ©   (2010-11-30 20:30) [32]

1. Не имеет смысла запускать в потоке то, чем нет возможности управлять. Например, запрос, который нельзя прервать. А если пресловутый "кверик" можно "снять" (не знаю как в уракле, а в АДО есть т.н. асинхронный режим, позволяющий не ждать завершения выполнения запроса)

2. Если запрос управляем, то где код, реализующий проверку на Terminate потока и соответственно "снимающий" кверик ?

3. На время выполнения "фоновых" запросов никоим образом не связывать их с визуальными компонентами - только по завершению.

4. Если результаты "фонового" запроса должны отображаться, то сам запрос (TXXXQuery) должен быть создан в основном потоке, а выполняться во вторичном, куда собственно и следует передавать указатель на квери при создании и запуске потока. Это позволит потоку благополучно помереть после завершения, а результатам - остаться для дальнейшего использования

5. Критические секции нужны лишь на создание объектов, но никак ни на сам ход выполнения запроса - для этого всего лишь нужно получать и обрабатывать сообщения сервера в "обычном", некритичном коде. Что легко делвется в "управляемом" запросе.

Все ИМХО


 
Игорь Шевченко ©   (2010-11-30 23:14) [33]

по сабжу - делал когда-то по дури заполнение грида отдельным потоком, типа данные бегают себе асинхронно, граждане довольные расходятся по домам и все такое.

Красиво, но нахрен не нужно.


 
Ega23 ©   (2010-12-01 00:55) [34]


> MsGuns ©   (30.11.10 20:30) [32]


Пункты 4 и 5 - чушь.
Также сильно подозреваю, что 1 и 2 - тоже. Под рукой справки нет.


 
Anatoly Podgoretsky ©   (2010-12-01 09:29) [35]

> Ega23  (01.12.2010 00:55:34)  [34]

Пункт 1 не чушь. Скажи что делать если запущен очень длительный запрос и его
надо прекратить нормально, а не аварийно?


 
Ega23 ©   (2010-12-01 09:58) [36]


> Пункт 1 не чушь.


Возможно. Я про асинхронный режим на память не силён, надо справку читать.


 
12 ©   (2010-12-01 10:37) [37]

Все, не тормозит вообще
> 1. Передать в тред ConnectionString
> 2. Передать в тред текст запроса
> 3. Создать соединение с БД, создать DataSet
> 4. Выполнить, дождаться конца
> 5. Отсигналить в основной тред, что данные зафетчены
> 6. передать сам НД через мессадж
И убиваю поток, когда пользователь новый запрос просит выполнить


> Красиво, но нахрен не нужно.

а боюсь, что так и получится
Но так, чисто для себя, чтоб на душе было комфортно :)


 
12 ©   (2010-12-01 10:40) [38]


> И убиваю поток, когда пользователь новый запрос просит выполнить

Да, и не даю выпонять еще один, пока не выполнился первый - иначе БД положат
А нафига все это - именно как ЮЗ сказал - чтоб у юзера не было сомнений, программа ли зависла или запрос долгий.


 
Ega23 ©   (2010-12-01 10:49) [39]


>  чтоб у юзера не было сомнений, программа ли зависла или
> запрос долгий.


Screen.Cursor := crSQLWait;
try
 DataSet.Open;
finally
 Screen.Cursor := crDefault;
ebd;


:)


 
Ega23 ©   (2010-12-01 10:51) [40]


> И убиваю поток, когда пользователь новый запрос просит выполнить


Зачем? Ставь его в Suspend. Соединение создано, НД создан.



Страницы: 1 2 вся ветка

Форум: "Начинающим";
Текущий архив: 2011.02.27;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.56 MB
Время: 0.004 c
15-1289831257
R_e_T_r_O
2010-11-15 17:27
2011.02.27
Записать из делфи в эксель


3-1253354851
Sergey__
2009-09-19 14:07
2011.02.27
Fbserver


6-1235138614
evgenij
2009-02-20 17:03
2011.02.27
SSH 2


15-1289322690
blacky1979
2010-11-09 20:11
2011.02.27
Посоветуйте компонет для отрисовки кинозала


2-1291622653
Демерго
2010-12-06 11:04
2011.02.27
Дублирование Showmessage





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский