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

Вниз

Поведение ADOConnection в многопоточном приложении   Найти похожие ветки 

 
Ega23 ©   (2005-11-08 16:46) [0]

Ситуация следующая:
Есть некая система с достаточно большим количеством объектов. У каждого из объектов есть поле Status, и это свойство изменяется в реальном времени по неким событиям (как из пользовательского интерфейса, так, например, и по сетевому событию). Каждый из этих объектов имеет своё отображение в БД.
Теоретически, событие обновления статуса объекта должно происходить по-принципу "плюнул и забыл", т.е. не нужно дожидаться выполнения команды.
В реальной же жизни приложение всё-таки ждёт результат выполнения ADOQuery.ExecSQL, что естественно сказывается на времени обработки сообщения.
После некоторых раздумий было принято решение вынести обновления статусов объектов в отдельный поток. Но тут встала другая проблема: все запросы работают через один ADOConnection, у которого есть свойство State. И которое далеко не всегда только stOpen.
В связи с этим возникает вопрос: как можно обойти данную проблему? Плодить отдельный коннект на каждый поток? Проверять статус ADOConnection во всех потоках? Писать наследника от TADOQuery, где анализировать изменение ADOConnection.State?

В общем, поделитесь мыслями...


 
WondeRu ©   (2005-11-08 17:19) [1]

Я бы сделал так:
Создается отдельный поток-обработчик, имеющий единственный ADOConnection. В этом потоке создается очередь (хоть TThreadList) сообщений от ваших объектов, которая постоянно (при наличии события в ней) записывается в БД.


 
Ega23 ©   (2005-11-08 17:28) [2]


> WondeRu ©   (08.11.05 17:19) [1]


Не понял: у дополнительного потока всё-таки СВОЙ коннект, или нет? Или на приложение в целом создаётся отдельный поток, в котором идёт всё общение с базой?


 
Silver Alex ©   (2005-11-08 17:40) [3]

а в чем собственно сложность?и при чем здесь вообще ADOConnection.State?  Наверное на каждый обьект(что за обьект, какой именно?) создавать поток и уже в нем(в потоке) производить свои вычисления.А несколько коннектов зачем, тоже не надо? Проблема выглядит какой-то надуманной.Не могу уловить, возможно не понял самой задачи.


 
Bronco ©   (2005-11-08 17:43) [4]


> Ega23 ©   (08.11.05 17:28) [2]

Если нет необходимости работать с транзакциями, то можешь вобще без ADOConnecton обойтись. ADOQuery имеет собственный ConnectionString
Или, как вариант, держать коннекцию постоянно открытой.
В противном случае, те участки кода, которые открывают-закрывают коннекцию и работают с данными скорее всего придется защищать с помощью критических секций или чего-то еще.


 
Ega23 ©   (2005-11-08 17:48) [5]


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


Проблема в том, что при запуске прототипа было получено исключение, что-то типа: "Connection is busy". Ведь через этот коннект не только команды на обновление состояния идут.


 
Silver Alex ©   (2005-11-08 17:49) [6]

>>Bronco ©   (08.11.05 17:43) [4]
>>которые открывают-закрывают коннекцию

парни, а вы что открываете-закрываете коннект с базой больше чем один раз? не советую вам так делать.Один коннект на все приложение, один раз открыли при старте и при закрытии программы один раз закрыли. Или зачем тогда вообще это конекшен.


 
Ega23 ©   (2005-11-08 17:50) [7]


> Если нет необходимости работать с транзакциями, то можешь
> вобще без ADOConnecton обойтись. ADOQuery имеет собственный
> ConnectionString
> Или, как вариант, держать коннекцию постоянно открытой.


Коннект и так постоянно открыт. Его никто не закрывает.
А если для каждого ADOQuery свой коннект открывать... Это не есть гуд.


 
isasa ©   (2005-11-08 17:53) [8]

1. Если инициализация ADO выполнена "по умолчанию" (с CoInitFlags=-1, модель STA), то по поводу потоков трудно что-то сказать.
2. А почему-бы не воспользоваться напрямую TADOQuery.ConnectionString, минуя TADOConnection?


 
ANB ©   (2005-11-08 17:53) [9]


> Ega23 ©   (08.11.05 17:50) [7]

В случае с ораклом при паралельной многопоточке я заводил отдельные сессии для каждого потока. Иначе - жуткие грабли. Для MS SQL я бы сделал так же.


 
Ega23 ©   (2005-11-08 17:54) [10]


> Один коннект на все приложение, один раз открыли при старте
> и при закрытии программы один раз закрыли. Или зачем тогда
> вообще это конекшен.


Вот-вот. Я тоже придерживаюсь такого мнения. Проблема в том, что основное приложение "сосёт" из БД различные выборки, причём достаточно часто. И при этом некая часть этого приложения (тот самый дополнительный поток) работает как "плюнул и забыл".
Сейчас в качестве промежуточного решения проблемы в дополнительном потоке вставлена проверка состояния ADOConnection. Если не stExecuting или stFetching - то пишем данные, иначе - ждём.


 
Silver Alex ©   (2005-11-08 17:55) [11]

>>Ega23 ©   (08.11.05 17:48) [5]

не понял, что такое прототип? обрисуй ситуации конкретней как-то, что за обьекты, что за события. Когда надо вызывать, что записывать в базу или читать. "Connection is busy" когда именно вываливается?не думаю что это TADOConnection, ни разу не встречал.Может сам сервер, хотя утверждать не буду. Надо больше информации


 
Ega23 ©   (2005-11-08 17:56) [12]


> 2. А почему-бы не воспользоваться напрямую TADOQuery.ConnectionString,
>  минуя TADOConnection?


Да потому, что это на N запросов получается N коннектов. И на сервере у каждого из них СВОЙ ProcessID.


 
isasa ©   (2005-11-08 17:56) [13]

Silver Alex ©   (08.11.05 17:49) [6]
Один коннект на все приложение, один раз открыли при старте и при закрытии программы один раз закрыли.


А если потоков много. ISAPI, например.


 
isasa ©   (2005-11-08 17:59) [14]

Да потому, что это на N запросов получается N коннектов.

Один поток - одно коннекшн.
Много потоков - много коннекшн.


 
Silver Alex ©   (2005-11-08 18:02) [15]

>>isasa ©   (08.11.05 17:56) [13]
>>А если потоков много. ISAPI, например.

если нельзя, но очень надо, то конечно можно :)
а если лицензий на базу пять штук и работает пять человек, то как тогда быть , если твоя прога может наплодить кучу коннектов? Думаю надо по ситуации смотреть, но вообще достаточно для одной программы одого коннекта, имхо


 
isasa ©   (2005-11-08 18:06) [16]

Я не понимаю, что смущает?
Каждый поток имеет свое соединение. Иначе нарываемся на ряд вопросов.
1.Кто открывает соединение?
2.Кто закрывает соединение?
3.Маршаллинг соединения в поток(если надо, а может не надо)?

Ставим себе барьеры и мужественно их преодолеваем? :)


 
Ega23 ©   (2005-11-08 18:08) [17]


> не понял, что такое прототип? обрисуй ситуации конкретней
> как-то, что за обьекты, что за события. Когда надо вызывать,
>  что записывать в базу или читать. "Connection is busy"
> когда именно вываливается?не думаю что это TADOConnection,
>  ни разу не встречал.Может сам сервер, хотя утверждать не
> буду. Надо больше информации
>


Под прототипом я имел ввиду добавление дополнительного потока.

Блин, долго объяснять.
В общем так: есть система безопасности. Всякие датчики-фигатчики и т.п. Всё это завязано в сеть. И есть АРМ (автоматизированное рабочее место) мониторинга системы. Там красивая графика, всякие гриды и прочие пользовательские прибамбасы. Суть работы такова: какой-то датчик изменил своё состояние (допустим из "нормального" в "тревожное"). Контроллер датчика отправляет это сообщение в сеть. АРМ его ловит, определяет кому оно адресовано, изменяет статус данного датчика в БД (это тот самый дополнительный поток) и отображает изменение состояния на экране. А, ещё протоколирует это дело.
Так вот, на update состояния съедается порядка 15 мс. В принципе это нормально, но если запускать этот update из основного потока приложения, то эти 15 мс. приложение ждёт ответа. А это уже нехорошо.

При попытки вынесения этих update-тов в отдельный поток нарвались на исключение Connection is busy. Т.е. что-то в этот момент времени выполнялось через данный коннект из основного приложения.


 
isasa ©   (2005-11-08 18:10) [18]

Да, еще :)
Традиционно.
4. Совместное использование (возня с критическими секциями)?


 
Silver Alex ©   (2005-11-08 18:12) [19]

>>Ega23 ©   (08.11.05 18:08) [17]

делаешь там все через Synchronize ?


 
isasa ©   (2005-11-08 18:14) [20]

Ega23 ©   (08.11.05 18:08) [17]

Точно сделал-бы с отдельным потоком + TADOQuery.ConnectionString + CursorLocation:=clServer; ИМХО


 
Bronco ©   (2005-11-08 18:14) [21]


> Ega23 ©   (08.11.05 17:56) [12]
>
>
> Да потому, что это на N запросов получается N коннектов.
>  И на сервере у каждого из них СВОЙ ProcessID.

А я вобще с трудом себе представляю работу N потоков через один коннект.
Тем более, если важна скорость, сам бог велел создать N коннектов.
Потому как даже если сделать всю работу с данными потокобезопастной, как предложили в [18], то это так же будет отъедать время (ожидание завершения)


 
Ega23 ©   (2005-11-08 18:14) [22]


> Каждый поток имеет свое соединение. Иначе нарываемся на
> ряд вопросов.
> 1.Кто открывает соединение?
> 2.Кто закрывает соединение?
> 3.Маршаллинг соединения в поток(если надо, а может не надо)?
>
>


1. Основной поток при старте.
2. Основной поток при закрытии.
3. Дык не проблема...

Коннект - это тоннель к базе, по которому гоняются составы-транзакции. Если поток один - всегда в тоннеле будет только один состав. Или "туда", или "сюда". А вот если потока 2, то есть вероятность столкновения этих составов. Таким образом, нужен или новый тоннель для дополнительного потока, либо семафор на главном. В качестве семафора можно использовать ADOConnection.State
В силу ряда причин не хочется иметь на сервере несколько разных процессов. Поэтому работа с одним коннектом - более предпочтительна.


 
Ega23 ©   (2005-11-08 18:18) [23]


> делаешь там все через Synchronize ?


Это вообще не я делаю. Это коллега мучается. На мне - серверная часть.

Просто сейчас тестируем альфа-версию релиза. Получили серьёзные "тормоза" при моделировании пиковой загрузки системы. Вот пытаемся оптимизировать. Я на сервере индексы строю, Лёха вот с потоком экперементирует...   :о)


 
isasa ©   (2005-11-08 18:20) [24]

Ega23 ©   (08.11.05 18:14) [22]
Ема-е ну сколько времени занимает транзакция с обновлением одной записи в индексированой таблице.


 
Silver Alex ©   (2005-11-08 18:22) [25]

>>Bronco ©   (08.11.05 18:14) [21]

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

И еще раз повторюсь, вот как сразу видно что все работают на пиратском ПО, никто даже не задумывается что лишние конекты выльются заказчику в лишние деньги


 
isasa ©   (2005-11-08 18:23) [26]

Да, что-то притормозил. Домой пора.
А в общем коннекте ты не сможеш поиграться с CursorLocation.
А нодо бы, по идее.


 
Silver Alex ©   (2005-11-08 18:25) [27]

>>Ega23 ©   (08.11.05 18:18) [23]

понимаю :)

оптимизация уже написаного приложения, вообще интересный кусок работы


 
Ega23 ©   (2005-11-08 18:26) [28]


> Ема-е ну сколько времени занимает транзакция с обновлением
> одной записи в индексированой таблице.
>


15 мс. Это нормально. Но в основном потоке, где один такт порядка 100 мс - это уже много.


 
Ega23 ©   (2005-11-08 18:28) [29]


> оптимизация уже написаного приложения, вообще интересный
> кусок работы


Это нормально. Нельзя же было ещё на этапе проектирования такие вещи учесть. Вот сейчас статистику работы наберём и будем анализировать.


 
isasa ©   (2005-11-08 18:29) [30]

Ega23 ©   (08.11.05 18:26) [28]
Ну так ...
И серверный курсор. И вперед ... А я домой.


 
Плохиш ©   (2005-11-08 18:35) [31]


> Ega23 ©   (08.11.05 17:54) [10]
> Вот-вот. Я тоже придерживаюсь такого мнения. Проблема в
> том, что основное приложение "сосёт" из БД различные выборки,
>  причём достаточно часто. И при этом некая часть этого приложения
> (тот самый дополнительный поток) работает как "плюнул и
> забыл".

А если один коннект для "сосёт" из БД различные выборки и один для "плюнул и забыл"


 
Ega23 ©   (2005-11-08 18:50) [32]


> А если один коннект для "сосёт" из БД различные выборки
> и один для "плюнул и забыл"


Если мне не изменяет память, то в MSDE есть ограничение на число коннектов к БД. Плюс разные пространства выполнения для каждого из ProcessID. Тоже, в общем-то, грабли...

Нет, конечно, если с одим коннектом ничего сделать нельзя, то будем дополнительный вводить. А точнее, как минимум 2 - один для обновления оперативных состояний, второй - для протоколирования данных.
Но лучше всё-таки через один найти решение...


 
Johnmen ©   (2005-11-08 23:19) [33]

>Ega23 ©

А чем смущает "каждому потоку - свой коннект" ?


 
sniknik ©   (2005-11-09 01:32) [34]

> Под прототипом я имел ввиду добавление дополнительного потока.
> Блин, долго объяснять.
> ...
> Так вот, на update состояния съедается порядка 15 мс. В принципе это нормально, но если запускать этот update
> из основного потока приложения, то эти 15 мс. приложение ждёт ответа. А это уже нехорошо.

так и запускай update из основного потока, тока ставь у команды ExecuteOptions = eoAsyncExecute, тогда основной поток не прервется ожиданием, ADO само выполнит команду в отдельном потоке и твои 15 мс. отработают на фоне основного такта - 100 мс.


 
sniknik ©   (2005-11-09 01:43) [35]

дополнение
> В реальной же жизни приложение всё-таки ждёт результат выполнения ADOQuery.ExecSQL, что естественно
> сказывается на времени обработки сообщения.
ADOCommand должен отработать немного быстрее... раз уж счет на милисекунды идет... плюс запрос обязательно должен быть параметризированным а не генерироваться на лету.


 
Polevi ©   (2005-11-09 08:01) [36]

все давно придумано уже
создаешь пул потоков в каждом свой коннекшн
отдаешь запрос пулу и забываешь
можно пул наращиваемый для масштабируемости


 
Ega23 ©   (2005-11-09 09:37) [37]


> А чем смущает "каждому потоку - свой коннект" ?

и

> все давно придумано уже
> создаешь пул потоков в каждом свой коннекшн
> отдаешь запрос пулу и забываешь
> можно пул наращиваемый для масштабируемости


Я ограничен числом коннектов к БД, т.к. MSDE использую.


 
Ega23 ©   (2005-11-09 09:38) [38]


> sniknik ©   (09.11.05 01:32) [34]


Это интересно. Спасибо, обязательно попробуем!


 
ANB ©   (2005-11-09 11:31) [39]


> Ega23 ©   (09.11.05 09:38) [38]

Такс. Если основной коннект будет делать запросы из той же таблицы, которая апдейтится другим коннектом, то MS SQL сам тебя тормознет на время выполнения транзакции обновления (т.е. селект не выполнится пока апдейт не закончится. Да и другие апдейты будут ждать. Я уже наступал на эту граблю). Я бы посмотрел в сторону кэширования поступления инфы от датчиков, чтобы затора из-за базы не было.


 
Ega23 ©   (2005-11-09 12:11) [40]


> Если основной коннект будет делать запросы из той же таблицы,
>  которая апдейтится другим коннектом, то MS SQL сам тебя
> тормознет на время выполнения транзакции обновления (т.е.
>  селект не выполнится пока апдейт не закончится


Низачот. Это всё регламентируется Isolation Level"ом. Я могу и "грязное чтение" делать (собственно, я его и делаю). For Browse которое.



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

Форум: "Базы";
Текущий архив: 2006.01.01;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.58 MB
Время: 0.01 c
2-1134429871
timerlan
2005-12-13 02:24
2006.01.01
обявить переменную


14-1133426364
VictorT
2005-12-01 11:39
2006.01.01
Пропал Ketmar, тут его многие знали, может, кто межет чем-то


2-1134220818
Witys
2005-12-10 16:20
2006.01.01
создание калькулятора


3-1130831948
Александр Я.
2005-11-01 10:59
2006.01.01
Асы Delphi! Помогите с выбором БД.


2-1134413280
Nikos
2005-12-12 21:48
2006.01.01
Ошибка при компиляции





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