Russian Qt Forum

Qt => Базы данных => Тема начата: demiurg от Сентябрь 18, 2011, 16:00



Название: БД и многопоточность
Отправлено: demiurg от Сентябрь 18, 2011, 16:00
Незнаю где тему создать толи в БД толи в многопоточных приложениях .  :)

Хочу в многопоточном TCP сервере подключаться к БД(MySQL)  и сохранять данные от клиентов в неё.  Появились вопросы по реализации такой структуры
1) Насколько я понял нужно создавать отдельное подключение в каждом потоке ?
2) Нужно ли именовать это подключение или же оно проименуюется по дефолту  и одинаковые имена не вызовут ошибку из разных потоков?
3) Нужно ли блокировать как то БД? Или же пересечение данных из разных подключений исключается?
Ну и чтобы не создавать ещё одну тему в другом разделе такой вопрос :
Т.к. приложение ответственно по времени , а каждый клиент при подключении выдаёт данных не более 20 Кб и по времени не более нескольких секунд - решил выделить каждому клиенту по потоку( вопреки общественному мнениею  ;D ) . Вопрос - а какой максимальное кол-во потоков выдержит сервер на WinServer2003? Т.е. сотню например он выдержит?



Название: Re: БД и многопоточность
Отправлено: LisandreL от Сентябрь 18, 2011, 17:09
1) Да.
2) Нужно уникальное имя (я включал в имя адрес потока).
3) Зависит от логики работы. Атомарные изменения нужно заключать в транзакциях.
Возможно есть ещё ограничения в зависимости от системы хранения (MyISAM, InnoDB …) - точно не скажу.
4) Даже на не серверной винде приложение может запустить 800+ потоков.
Общественное мнение не потому рекомендует не делать слишком много потоков, что ОС их не выдержит, а потому, что так вы будете терять много времени на переключение между потоками и «ответственного по времени» будет в итоге тратиться больше.


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 18, 2011, 18:01
1) Да.
2) Нужно уникальное имя (я включал в имя адрес потока).
3) Зависит от логики работы. Атомарные изменения нужно заключать в транзакциях.
Возможно есть ещё ограничения в зависимости от системы хранения (MyISAM, InnoDB …) - точно не скажу.
4) Даже на не серверной винде приложение может запустить 800+ потоков.
Общественное мнение не потому рекомендует не делать слишком много потоков, что ОС их не выдержит, а потому, что так вы будете терять много времени на переключение между потоками и «ответственного по времени» будет в итоге тратиться больше.

3) Логика простая - пришли данные, считался идентификатор,  и занеслись в таблицу с заполением поля соответствующему идентификатору. Отключение от сервера.
4)  Понятно , спасибо за разъяснения. Думаю не критично когда время передачи и обработки -  секунды а данных и 20Кб не наберётся.  

Цитировать
Возможно есть ещё ограничения в зависимости от системы хранения (MyISAM, InnoDB …) - точно не скажу.

Вот это интересно, что лучше для таких задач. Нужно "загуглить"...



Название: Re: БД и многопоточность
Отправлено: LisandreL от Сентябрь 18, 2011, 19:51
Ах да, ещё учтите, что у MySQL есть ограничение на количество одновременных подключений (впрочем настраиваемое).


Название: Re: БД и многопоточность
Отправлено: Whiplash от Сентябрь 19, 2011, 08:24
На Хабре как-то была статья про многопоточное приложение на Qt работающее с БД через singleton-класс. Т.е. собсно подключение одно на все потоки, которое обеспечено синглтоном в отдельном потоке. Потоки посылают ему сигналы с запросами или с параметрами запросов, а поток подключения выполняет это на БД.


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 19, 2011, 09:49
На Хабре как-то была статья про многопоточное приложение на Qt работающее с БД через singleton-класс. Т.е. собсно подключение одно на все потоки, которое обеспечено синглтоном в отдельном потоке. Потоки посылают ему сигналы с запросами или с параметрами запросов, а поток подключения выполняет это на БД.
ууу, чо так сложно, я есчо не вырос до этого уровня. Да и если подключение одно - смысл многопоточности теряется. БД то может и  100 и 200 подключений выдерживать.  А если "зависнет" поток - то основное приложение не встанет( по идее).


Название: Re: БД и многопоточность
Отправлено: Странник от Сентябрь 19, 2011, 09:59
Да и если подключение одно - смысл многопоточности теряется. БД то может и  100 и 200 подключений выдерживать.  А если "зависнет" поток - то основное приложение не встанет( по идее).
и почему же теряется смысл, любопытно? запросы клиентов по-прежнему обрабатываются параллельно, а запись данных в БД последовательная в любом случае. но при одном подключении вы избавляетесь от накладных расходов на подключение-отключение клиентов к БД.


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 19, 2011, 11:24
Да и если подключение одно - смысл многопоточности теряется. БД то может и  100 и 200 подключений выдерживать.  А если "зависнет" поток - то основное приложение не встанет( по идее).
и почему же теряется смысл, любопытно? запросы клиентов по-прежнему обрабатываются параллельно, а запись данных в БД последовательная в любом случае. но при одном подключении вы избавляетесь от накладных расходов на подключение-отключение клиентов к БД.

Да, не подумал, токма всёравно без примера не смогу реализовать  :-[  У мну есть готовый многопоточный сервер- с ним я разобрался , а как реализовать этот singleton - чтото из разряда магии  ;D


Название: Re: БД и многопоточность
Отправлено: Странник от Сентябрь 19, 2011, 11:38
да вот собственно упомянутая выше статься с Хабра (http://habrahabr.ru/blogs/qt_software/52536/), подробно и с примерами.


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 19, 2011, 11:46
Упс , да там не всё так сложно. Люблю примеры , надеюсь заработает  :) (у меня  ;D)  Спасибо  ,пойду шаманить ...


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 19, 2011, 19:38
Цитировать
да вот собственно упомянутая выше статься с Хабра, подробно и с примерами.
Попытался скомпилить этот "синглетон", но на 
Код:
class DatabaseAccessor
 {
public:
     static DatabaseAccessor* getInstance();
     static QString dbHost;
     static QString dbName;
     static QString dbUser;
     static QString dbPass;

public slots:
     void executeSqlQuery(QString);
     void validateUser(QString, QString);

private:

     DatabaseAccessor();
     DatabaseAccessor(const DatabaseAccessor& );
     DatabaseAccessor& operator=(const DatabaseAccessor& );
     QSqlDatabase db;
 };
выдаёт Class declarations lacks Q_OBJECT macro.
 
а если добавить макросы Q-OBJECT - говорит что незнает что такое  dbHost;dbName;dbUser;dbPass;
Или это пример условно рабочий?


Название: Re: БД и многопоточность
Отправлено: BRE от Сентябрь 19, 2011, 19:42
Это же хабр. :)
Что бы использовать сигналы/слоты класс должен быть наследником QObject и иметь макрос Q_OBJECT.
В таком виде "декларация слотов" как бы бесполезна.


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 19, 2011, 19:50
Это же хабр. :)
Что бы использовать сигналы/слоты класс должен быть наследником QObject и иметь макрос Q_OBJECT.
В таком виде "декларация слотов" как бы бесполезна.


Я это предвидел , поэтому написал так
Код:
class DatabaseAccessor:public QObject
 {
Q_OBJECT
public:
     static DatabaseAccessor* getInstance();
     static QString dbHost;
     static QString dbName;
     static QString dbUser;
     static QString dbPass;
private:

     DatabaseAccessor();
     DatabaseAccessor(const DatabaseAccessor& );
     DatabaseAccessor& operator=(const DatabaseAccessor& );
     QSqlDatabase db;
 };

Но тогда чёт вылазит ошибка вида
 undefined reference to `DatabaseAccessor::dbName' итд при попытке обращения.

Вроде ж явно объявлены. Ничо не понятно... ООП не моё  :-[


Название: Re: БД и многопоточность
Отправлено: BRE от Сентябрь 19, 2011, 19:52
Статические переменные нужно определить в .cpp файле, у тебя они только декларированы.
В .cpp файле:
Код
C++ (Qt)
QString DatabaseAccessor::dbHost;
QString DatabaseAccessor::dbName;
...
 


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 19, 2011, 20:35
Ну так я их и определял

так

Код:
DatabaseAccessor::DatabaseAccessor(QObject *parent)               
 {
     DatabaseAccessor::dbHost="localhost";
     db=QSqlDatabase::addDatabase("QMYSQL");
     db.setHostName(dbHost);
     db.setDatabaseName(dbName);
     db.setUserName(dbUser);
     db.setPassword(dbPass);
     if (db.open())
     {
         qDebug("connected to database");
     }
     else
     {
         qDebug("Error occured in connection to database");
     }
 }
пишет что уе задекларировано

и так
Код:
int main(int argc, char **argv) {
    QCoreApplication app(argc, argv);
    DatabaseAccessor::dbHost="localhost";
    DatabaseAccessor::getInstance();

Ниего не меняется.

Вообщем , чот сырец какой то, явно не моего уровня.
А где бы найти нормальное описание создания классов , только практически а не теория...


Название: Re: БД и многопоточность
Отправлено: BRE от Сентябрь 19, 2011, 20:46
Ну так я их и определял
Ты их в функции что ли определял?

Код
C++ (Qt)
DatabaseAccessor::dbHost;
DatabaseAccessor::dbName;
 
DatabaseAccessor::DatabaseAccessor(QObject *parent)              
{
    db.setHostName(dbHost);
    db.setDatabaseName(dbName);
    ...
 

и так
А так ты им значения присваиваешь.

А где бы найти нормальное описание создания классов , только практически а не теория...
Рекомендую любую книгу по C++. ;)


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 19, 2011, 21:01
Цитировать
Ты их в функции что ли определял?

Код
C++ (Qt)
DatabaseAccessor::dbHost;
DatabaseAccessor::dbName;
 
DatabaseAccessor::DatabaseAccessor(QObject *parent)              
{
    db.setHostName(dbHost);
    db.setDatabaseName(dbName);
    ...
 

Аааа....дела...


Цитировать
Рекомендую любую книгу по C++. ;)

Да есть , читал. Всё какието примеры отдалёные от реальности. Нужна просто книга с примерами. А таких нет практически для высокого уровня, когда уже классы свои создавать надо. Каша в голове получается-  проблема в том что в С++ пришёл через asm->С. Там всё явно и прямолинейно. Правда и писанины в разы больше.

ЗЫ Спс, заработало, даже к базе конектица  :)



Название: Re: БД и многопоточность
Отправлено: BRE от Сентябрь 19, 2011, 21:13
Каша в голове получается-  проблема в том что в С++ пришёл через asm->С. Там всё явно и прямолинейно. Правда и писанины в разы больше.
Поэтому и рекомендую вначале хорошо разобраться с инструментом (C++), а потом уже подходить к Qt.
А на счет пути... я тоже шел по тому же пути и могу сказать что на каждом шаге есть свои тонкости. :)


Название: Re: БД и многопоточность
Отправлено: Denis.Rassvetniy от Сентябрь 21, 2011, 05:33
Цитировать
Рекомендую любую книгу по C++. ;)

Да есть , читал. Всё какието примеры отдалёные от реальности. Нужна просто книга с примерами. А таких нет практически для высокого уровня, когда уже классы свои создавать надо.
[/quote]

Рекомендую Р. Лафоре "Объектно-ориентированное программирование в C++"


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 21, 2011, 09:12
Спс. Скачал, читаю...

Я вот тут подумал. Если сделать этот синглетон, то в той его реализации после отправки запроса придётся стопорить поток msleep*ами  и ждать ответа, т.е. новые данные с клиента , если и придут, то не обработаются - так а в чём тогда выигрыш? А если делать подключение к БД в каждом потоке , то всегда есть статичное время подключения к БД ( ну допустим 1-2 секунды). 

Или как то реализовать на сигналах и слотах. А как тогда сигнал передать именно тому объекту, от которого запрос(сигнал на запрос) пришёл  ???


Название: Re: БД и многопоточность
Отправлено: BRE от Сентябрь 21, 2011, 09:32
А если делать подключение к БД в каждом потоке , то всегда есть статичное время подключения к БД ( ну допустим 1-2 секунды). 
А ты используй пул потоков и для каждого потока используй свое подключение.
Тогда рабочие потоки не придется пересоздавать и переподключать к БД.


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 21, 2011, 10:01
Т.е. не разрушать потоки после отключения клиентов... А при подключении связывать сигналы отключения и приёма со слотами определённого потока, выбранного из пула? Так получается? Но тогда нужно будет держать по 100 потоков( по клиенту на поток) - а сильно ли это нагрузит систему...

ЗЫ Да , видать надо было в другом разделе тему создавать...   


Название: Re: БД и многопоточность
Отправлено: LisandreL от Сентябрь 21, 2011, 10:35
Но тогда нужно будет держать по 100 потоков( по клиенту на поток) - а сильно ли это нагрузит систему...
Qt потоки != потоки системы. Cистемный поток существует только пока QThread находится в run.
QThread до start() и после finished() из системных ресурсов потребляет только немного памяти.


Название: Re: БД и многопоточность
Отправлено: BRE от Сентябрь 21, 2011, 10:55
Т.е. не разрушать потоки после отключения клиентов... А при подключении связывать сигналы отключения и приёма со слотами определённого потока, выбранного из пула? Так получается? Но тогда нужно будет держать по 100 потоков( по клиенту на поток) - а сильно ли это нагрузит систему...
Не нужно ничего разрушать и никого отключать. :)
Ты сразу создаешь несколько рабочих потоков (например 4 или 10 или 25 :) ) и открываешь для каждого свое подключение.
Пока работы нет, эти потоки спят. Появился запрос к БД ты кладешь его в очередь, первый свободный поток просыпается и начинает его обрабатывать. По окончании обработки запроса этот поток заснет, если других запросов в очереди нет или возьмет очередной запрос из очереди.



Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 21, 2011, 11:18
Ааа, даже так... То что надо. А очередь можно реализовать перебором QList или QMap ? Т.е. переираешь теже 25 потоков и ищеш первый который свободный, например ввести переменную , которая покажет что поток свободен.


Название: Re: БД и многопоточность
Отправлено: BRE от Сентябрь 21, 2011, 11:25
Ааа, даже так... То что надо. А очередь можно реализовать перебором QList или QMap ? Т.е. переираешь теже 25 потоков и ищеш первый который свободный, например ввести переменную , которая покажет что поток свободен.
Доверь поиск свободных потоков ОС.
Почитай:
http://www.prog.org.ru/topic_16083_15.html
http://www.prog.org.ru/topic_14426_60.html


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 21, 2011, 12:00
Хм, не уловил ,так сказать, идеи. Работать через   QThreadPool?

Сейчас в принципе работает так( но пока и нет 100 подключений)

Код:
void EchoServer::incomingConnection(int socketDescriptor) {
    EchoThread *thread = new EchoThread(socketDescriptor, this);
    connect(thread, SIGNAL(finished()), this, SLOT(removeThread()),
            Qt::DirectConnection);
    m_threads.append(thread);
    thread->start();
}

void EchoServer::removeThread(){
    EchoThread *thread = qobject_cast<EchoThread*>(sender());
    m_threads.removeAt(m_threads.indexOf(thread));
    thread->deleteLater();
}

Это пример из Земского  , для чайников  ;D  Мне подходит( Пока что. Но думаю метод RUN и слоты связанне с ним не поменяются)  .
Получается , вместо удаления потока мы просто его "освобождаем", но как это сделать  -я не понял. ЧайникСсс  :) А есть хотябы сырой пример?  - чтобы начать "копать" ...


Название: Re: БД и многопоточность
Отправлено: BRE от Сентябрь 21, 2011, 12:42
Темы не дочитал до конца? :)
Там и примеры есть и наброски.


Название: Re: БД и многопоточность
Отправлено: demiurg от Сентябрь 21, 2011, 14:00
Дочитал вот сейчас. Стало оформляться.

Получается в основном потоке принимаю подключения и заношу в очередь( например в QList) , и шлю сигнал всем потокам , что очередь не пустая. По очереди возникают слоты, в которых обрабатываем эту очередь, изымая клиентов из очереди ( а как быть с тем что может опять возникнуть вызов) . После окончания работы(например в слоте отключения клиента от сервера)  вызываем метод wait который "усыпляет поток". ТАк? Или всё же всё сложнее ?