Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

dbExsress, одновременный Open() в разных потоках

16K
25 июня 2009 года
CCCP
10 / / 10.08.2006
Проблемы возникают при работе с БД, используя dbExpress. Точнее при МНОЖЕСТВЕННЫХ и ОДНОВРЕМЕННЫХ соединениях с СУБД (MS SQL, или Oracle, или Informix).

Проблему хорошо показать на примере, посему для примера и тестирования сделал вот такое:
1. Три компонента на форме: SQLConnection1,SQLQuery1 и Button1;
2. SQLQuery1->SQLConnection = SQLConnection1
3. SQLConnection1 настроен на соединение с СУБД (адреса, логины, пароли как положено)
4. При старте программы сразу SQLConnection1->Open()
5. По нажатию кнопки Button1 запускается цикл на 500 оборотов, в каждом обороте запускается НОВЫЙ поток
6. В каждом потоке :
- создаётся новый TSQLConnection : New_SQLConnection = SQLConnection1->CloneConnection();
- создаётся новый TSQLQuery : New_SQLQuery = new TSQLQuery(NULL);
- соединяется New_SQLQuery с New_SQLConnection : New_SQLQuery->SQLConnection = New_SQLConnection;
- выполняем какой-то запрос к БД
- разъединяемся New_SQLConnection1->Close();
- очищаем память delete New_SQLConnection1; delete New_SQLQuery;

Из этих 500 соединений удачно выполняются от 300 до 450, остальные, на шаге SQLConnection1->CloneConnection() отбиваются с разными ошибками : нет соединения, или сервер не найден, или всех лучше ошибка - Accsess Violation. Точный текст ошибки зависит от используемой СУБД.

Если делать не клонирование, а ручное заполнение параметров и после выполнить SQLConnection1->Open(), то ошибки вылетят те же на шаге Open(). То есть, разницы с клонированием нет.

Методом всяких тестов пришли к выводу - вылет происходит при МНОЖЕСТВЕННЫХ, ОДНОВРЕМЕННЫХ попытках создать соединение с БД. То есть, если открывать по очереди соединения (!) и даже не закрывать их, то все соединения выполняться. Если компьютер слабенький (не успевает он одновременно запустить столько потоков), то опять же проходит всё без ошибок. Чем сильнее ПК (брали для теста 4 разных) - тем больше ошибочных соединений из этих пяти сотен - значит чем больше потоков успевает запуститься одновременно, тем больше отбивается.

При чём ошибка ИМЕННО на клиентском месте, до сервера соединения и не доходит (проверяли - сервер ничего не отбивал). Начали грешить на параметр в Windows-е - разрешённое кол-во одновременных соединений TCP/IP. Запустили на Windows Server 2003, где таких разрешений 9999 - ошибки те же.

ВЫВОД : dbExpress при соединениии задействует что-то, что имеет ограниченый ресурс. Очень ограниченный . Прежде чем лепить какие-то заплатки в программу, избегая этой ошибки, надо выяснить ОТКУДА ЭТА ОШИБКА!!! Чего не хватает dbExpress???? Оперативки? Какого-то буфера сетевого?
294
25 июня 2009 года
Plisteron
982 / / 29.08.2003
Цитата: CCCP
Из этих 500 соединений удачно выполняются от 300 до 450, остальные, на шаге SQLConnection1->CloneConnection() отбиваются с разными ошибками : нет соединения, или сервер не найден, или всех лучше ошибка - Accsess Violation.

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

16K
25 июня 2009 года
CCCP
10 / / 10.08.2006
Цитата: Plisteron
Имхо, надо предусматривать синхронизацию потоков, чтобы очередной поток мог подключаться (и отключаться тоже) только в тот момент, когда нет других потоков, находящихся в процессе установки или завершения соединения.


Такой вариант уже опробовали и оставили его на совсем крайний случай - очень замедляет работу.
Для примера 2 теста:
В каждом новом потоке выпоняется:
-Соединение с БД
-Вставка в БД
-Разъединение

Тест №1:
Запускаем 500 таких потоков одновременно. Результат: 441 удачное соединение, 59 отбилось. [COLOR="Red"]Прошло всё за ~4.8 сек[/COLOR]

Тест №2:
Запускаем 500 таких потоков одновременно.
НО -> ставим синхронизацию на соединение : в один момент времени может соединяться только кто-то один. Практически это выпонение методов Open() ставиться в очередь. Вставка и разъединение остаётся без ограничений.
Результат: 500 удачных соединений, 0 ошибочных. [COLOR="Red"]Прошло всё за ~93 сек[/COLOR]

Это в 18 раз медленне. Программа - сервер, и инициировать таких соединений будет много, такой тормоз делать ОЧЕНЬ ПЛОХО!

11
25 июня 2009 года
oxotnik333
2.9K / / 03.08.2007
Цитата: CCCP

Тест №2:
Запускаем 500 таких потоков одновременно.
НО -> ставим синхронизацию на соединение : в один момент времени может соединяться только кто-то один. Практически это выпонение методов Open() ставиться в очередь. Вставка и разъединение остаётся без ограничений.
Результат: 500 удачных соединений, 0 ошибочных. [COLOR=Red]Прошло всё за ~93 сек[/COLOR]

Это в 18 раз медленне. Программа - сервер, и инициировать таких соединений будет много, такой тормоз делать ОЧЕНЬ ПЛОХО!


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

 
Код:
bool Connect = false;
do{
Connect = Connection->Open();
Sleep(1); // чтоб систему не грузило;
} while (!Connect);
16K
25 июня 2009 года
CCCP
10 / / 10.08.2006
Цитата: oxotnik333
В реале абсолютно одновременно на сервер никто стучаться не будет


проблема возникла не на этапе проектирования, а пришла уже из реала. Именно - стучались 1000 клиентов одновременно. И самое сложное - что так и должно быть.
А если ставить в очередь соединения(такая синхроницазия именно очередь делает), то временные замеры Вы виедли - в 18 раз разница. Значит одновременно стучаться можно... Не позволяет этого делать библиотека dbExpress или драйвера клиентских мест.
ADO - таких проблем не вызывает, но ADO само по себе ТАКОЕ приторможеное .... -> одновременный запуск 500, выне приведённых тестов, проходит за 116 сек.
Лучше в dbExpress ставить очередь - это 93 сек. для данного теста.

294
25 июня 2009 года
Plisteron
982 / / 29.08.2003
Цитата: CCCP
Такой вариант уже опробовали и оставили его на совсем крайний случай - очень замедляет работу.
Для примера 2 теста:
В каждом новом потоке выпоняется:
-Соединение с БД
-Вставка в БД
-Разъединение

Тест №1:
Запускаем 500 таких потоков одновременно. Результат: 441 удачное соединение, 59 отбилось. [COLOR=Red]Прошло всё за ~4.8 сек[/COLOR]

Тест №2:
Запускаем 500 таких потоков одновременно.
НО -> ставим синхронизацию на соединение : в один момент времени может соединяться только кто-то один. Практически это выпонение методов Open() ставиться в очередь. Вставка и разъединение остаётся без ограничений.
Результат: 500 удачных соединений, 0 ошибочных. [COLOR=Red]Прошло всё за ~93 сек[/COLOR]

Это в 18 раз медленне. Программа - сервер, и инициировать таких соединений будет много, такой тормоз делать ОЧЕНЬ ПЛОХО!


1. Вам шашечки или ехать?
2. Неужели нельзя один раз подключиться к БД, а потом из разных потоков (если уж так хочется многопоточность) пихать данные, используя одно соединение (естественно, с синхронизацией)?
3. Если уж так надо именно своё подключение в каждом потоке, можно сделать пул готовых подключений (допустим, 100 штук заранее) и раздавать их потокам по требованию, а когда готовые подключения исчерпываются, создавать новый пул.

16K
26 июня 2009 года
CCCP
10 / / 10.08.2006
Цитата: Plisteron
1. Вам шашечки или ехать?
2. Неужели нельзя один раз подключиться к БД, а потом из разных потоков (если уж так хочется многопоточность) пихать данные, используя одно соединение (естественно, с синхронизацией)?
3. Если уж так надо именно своё подключение в каждом потоке, можно сделать пул готовых подключений (допустим, 100 штук заранее) и раздавать их потокам по требованию, а когда готовые подключения исчерпываются, создавать новый пул.


Не поверите - вчера вечером дошли до этих решений....
Лучшим решением показался способ №3 (пул подключений), но поводу способа №2 терзают ОЧЕНЬ смутные сомнения, хочется таки разобраться в нём подробнее. Уже когда-то ранее решили - что в одном подключении всё будет ставиться в очередь и нам такое не подходит, надо одновременное выполнение, делали для каждого потока своё подключения.
Я уже провёл тест (это всё к тому же способу №2) - одно подключение в основном потоке, во многих потоках создаётся SQLQuery, SQLQuery присоединяются к этому подключению и выполняют запросы. Подключался к Oracl-у, мне там удобно смотреть кол-во открытых сессий и курсоров. В Oracle - открывается одна сессия и в ней множество курсоров.
И вот что меня ОЧЕНЬ интересует:
2.1 ЭТО МНОГОЗАДАЧНОСТЬ? Эти курсоры выполняются одновременно? У меня такое подозрение что по-очереди. Просто работу с очередью мы отдаём СУБД. Там где СУБД машина шустрая и заметить по скорости сложно - очередь или многопоточность.
2.2 Иногда вылетала ошибка [COLOR="Red"]AccessViolation[/COLOR] при попытке выполнить зпрос. Такое ощущение что как-то надо ограничивать кол-во одновременно открытых курсоров.

Пока провожу тесты по поводу способа №3. Надо выяснить : одновременно выполняющиеся запросы, каждый из которых имеет своё соединение (соединения открыты по-очереди) не будут также вылетать. Может запросы тоже что-то одно будут дёргать в драйверах dbExpress , и на этом одном вылетать. Одновременный Open() в разных потоках вылетал ведь из-за dbExpress. Может и одновременный TSQLQuery::ExecSQL тоже вылетит.

294
26 июня 2009 года
Plisteron
982 / / 29.08.2003
Цитата: CCCP
2.1 ЭТО МНОГОЗАДАЧНОСТЬ? Эти курсоры выполняются одновременно? У меня такое подозрение что по-очереди. Просто работу с очередью мы отдаём СУБД. Там где СУБД машина шустрая и заметить по скорости сложно - очередь или многопоточность.
2.2 Иногда вылетала ошибка [COLOR=Red]AccessViolation[/COLOR] при попытке выполнить зпрос. Такое ощущение что как-то надо ограничивать кол-во одновременно открытых курсоров.


2.1 Oracle может выполнять запросы асинхронно с использованием одного соединения, это многозадачность. Проблема в том, может ли это делать dbExpress? Я не знаю, но сомневаюсь. Попробуй непосредственно через OCI.
2.2 Вероятнее всего, здесь та же проблема, что и с одновременными подключениями -- нужна синхронизация.
Добавлено:
PS. Создавать кучу соединений с Oracle в одной программе -- дурной тон, ибо много серверных ресурсов расходуется. Дело в том, что Oracle при логине выполняет раннее связывание объектов с учётом прав доступа пользователя. Т.е. идеология такова: один раз подключился -- и работай.
PPS. Если запросы однотипные (допустим, все в одну таблицу и все с одними и теми же столбцами), настоятельно рекомендуется использовать запросы с параметрами, и парсить их всего один раз. В подобном случае лучше действительно пихать данные в БД не из каждого потока независимо, а передавать их в очередь, где отдельный поток будет подставлять данные в заранее пропарсенный запрос и выполнять.

16K
26 июня 2009 года
CCCP
10 / / 10.08.2006
Цитата: Plisteron
PS. Создавать кучу соединений с Oracle в одной программе -- дурной тон, ибо много серверных ресурсов расходуется. Дело в том, что Oracle при логине выполняет раннее связывание объектов с учётом прав доступа пользователя. Т.е. идеология такова: один раз подключился -- и работай.


Так как же быть с пулом соединений?! Это дурной тон или всё-таки нормаьно (ведь 100 соединений один раз выполняются и далее работа только с ними) .
P.S.: уже разарбытываю именно пул соединений, надеюсь это не очень дурной тон :)

9.3K
26 июня 2009 года
iridum
175 / / 26.08.2007
Мало того что 100 соединений, дак еще и каждое из отдельного потока ) жестяка...

ps. Мне кажеться если так, то уже лучше до 10 потоков, в каждом конекшн, в каждом потоке 100 нитей на каждого юзера
294
27 июня 2009 года
Plisteron
982 / / 29.08.2003
Цитата: CCCP
Так как же быть с пулом соединений?! Это дурной тон или всё-таки нормаьно (ведь 100 соединений один раз выполняются и далее работа только с ними) .
P.S.: уже разарбытываю именно пул соединений, надеюсь это не очень дурной тон :)


Это нормально. Я немного неправильно выразился: дурной тон открывать и тут же закрывать множество соединений. Хороший тон -- открыл сколько надо и работаешь с ними до завершения работы программы.
Т.е.

Цитата: CCCP
100 соединений один раз выполняются и далее работа только с ними

-- комильфо.

Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог