Форум: "Начинающим";
Текущий архив: 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