Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Вопрос по boost::asio


Автор: Artemon 26.2.2011, 16:10
Наслышан о том что с помощью asio можно написать сервер, который при прочих равных условиях выдержит большее число подключений чем сервер работающий по модели ОДИН КЛИЕНТ-ОДИН ПОТОК.

Вопрос:
Есть машинка с одноядерным процессором, на сервере производится длительная операция обращения к БД. Как в asio сделать так чтобы пока идет
работа с БД - остальные клиенты не проставивали ?

P.S.
С многопоточным сервером все понятно, пока идет длительная операция - остальные потоки работают, разделяя общее процессорное время.

Автор: Abyx 26.2.2011, 17:20
выносить операцию с бд в поток %)
я хз как связана ваша бд и asio

Автор: bsa 26.2.2011, 20:14
Artemon, asio - это аббревиатура от асинхронного ввода вывода.
Там смысл несколько отличный от стандартных представлений. Если тебе надо что-то сделать, то ты вызываешь соответствующий метод передавая ему функтор, который должен быть вызван по завершении операции. Когда операция завершается, этому функтору передается код завершения (ok или ошибка). И ты из этого функтора уже заказываешь выполнение следующего действия... Таким образом, ты никогда не сидишь и не ждешь, пока выполнится какое-либо действие - в это время может выполняться другое.

Например, у тебя есть твой вэб-сервер, работающий с БД. При запуске сервера ты ставишь задачу: установить TCP соединение с сервером БД

И запускаешь io_service.run()...
Как только у тебя происходит установка связи с БД вызывается соответствующий функтор, и если все в порядке, ты посылаешь команду авторизации... После ее отправки ты ставишь задачу ожидания результата авторизации. В случае успешного результата ты отправляешь команду на открытие БД... Короче, работа с БД установлена. Теперь можно открыть TCP порт 80 в режиме приема соединений, ставишь соответствующую задачу.

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

Автор: Artemon 26.2.2011, 22:05
Цитата

выносить операцию с бд в поток %)


Я ищу вариант чтобы от этого УЙТИ.

Цитата(bsa @  26.2.2011,  20:14 Найти цитируемый пост)
Когда ты их получишь, ты ставишь задачу оправки запроса к БД... В это же время может быть принят другой клиент... 


Каким образом он будет принят если основной поток (и единственный) трудится над выборкой из БД ?

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

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


Автор: bsa 26.2.2011, 22:14
Artemon, раз ты такие вопросы задаешь, значит ты не понимаешь, как работает asio.

постановка задачи занимает практически нулевое время. Другими словами, функция постановки возвращается тут же. Долгий запрос будет выполняться в "фоне". Т.е. ты не должен ждать, когда он завершится. Ты поставил задачу отправить запрос к БД и все. Когда задача будет выполнена будет вызвана твоя функция, в которой ты только поставишь задачу "принять данные от БД" и все. После успешного приема данных от БД, ты ставишь задачу "отправить данные клиенту"...

Посмотри внимательно примеры под asio.

Автор: Artemon 26.2.2011, 23:05
насколько я понял у asio есть 2 основных метода sync_read и sync_write в которые мы передаем  методы, которые выполнятся по завершению чтения или записи.

Допусти я сделал что-то типа  этого:

Код

void Read()
{
boost::sync_read(ReadHandler);
}

void ReadHandler()
{
   SELECT * FROM BIG_TABLE;

   start_accept_new_client();
}


Когда завершится чтение - начнет выполняться метод ReadHandler. Но с чего это он будет выполняться в Фоне ?


Автор: boostcoder 27.2.2011, 00:35
Цитата(Artemon @  26.2.2011,  23:05 Найти цитируемый пост)
у asio есть 2 основных метода sync_read и sync_write

нет.
есть синхронные(блокирующие): read() и write(). и есть асинхронные(не блокирующие): async_read() и async_write().

Цитата(Artemon @  26.2.2011,  16:10 Найти цитируемый пост)
Как в asio сделать так чтобы пока идет работа с БД - остальные клиенты не проставивали ?

по хорошему, должен быть пул потоков в котором выполняется asio::io_service::run.
в таком случае, если пул интеллектуальный, он сам, в зависимости от thread_sleep_time(не знаю как на русском сказать), производит регулирование числа потоков.
при этом, вы, свой долгий_запрос_к_БД, можете запостить как любую асинхронную задачу. смотрите: http://www.boost.org/doc/libs/1_46_0/doc/html/boost_asio/reference/io_service/post.html
это позволит интеллектуальному пулу потоков, учитывать время затрачиваемое на этот запрос. и он(интеллектуальный пул потоков) примет этот факт во внимание, и в зависимости от политики пула, он, возможно, будет добавлять/убавлять кол-во потоков.

Цитата(Artemon @  26.2.2011,  23:05 Найти цитируемый пост)
Когда завершится чтение - начнет выполняться метод ReadHandler. Но с чего это он будет выполняться в Фоне ?

не понял вопроса..

Автор: bsa 27.2.2011, 12:36
Artemon, ты все перепутал.
Код
void MyClass::onClientAccepted(Client *client, const boost::system::error_code &ec)
{
    if  (!ec) {
       startAccepting();//ставим задачу ожидания подключения следующего клиента
       client->startReading();
    }
}
void Client::onReceived(buffer &buf, const boost::system::error_code &ec)
{
      if (ec)
          return;
      //что-то тут делаем
      db.query(query, boost::bind(&Client::onQueryComplete, this, _1, _2));
}
void Client::onQueryComplete(buffer &buf, const boost::system::error_code &ec)
{
    //что-то
    socket_.async_write(..., boost::bind(&Client::onSended, this, ...), ...);
}

Автор: Artemon 27.2.2011, 18:30
boostcoder, 

Цитата(boostcoder @  27.2.2011,  00:35 Найти цитируемый пост)
при этом, вы, свой долгий_запрос_к_БД, можете запостить как любую асинхронную задачу. смотрите: http://www.boost.org/doc/libs/1_46_0/doc/h...rvice/post.html


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

На счет интеллектуальности - для начала хотелосьбы разобраться, удастся реализовать сервер используя лишь один основной поток + асинхронные вызовы asio.


Цитата(bsa @  27.2.2011,  12:36 Найти цитируемый пост)
//что-то тут делаем      db.query(query, boost::bind(&Client::onQueryComplete, this, _1, _2));

Каким образом данная строка выполнится асинхонно ?
Как раз таки я и думаю что затык будет именно в этом месте (возможно ошибаюсь).

Автор: boostcoder 27.2.2011, 18:47
Цитата(Artemon @  27.2.2011,  18:30 Найти цитируемый пост)
Подозреваю что эта асинхронная задача будет реализовываться с помощью потока. Если для каждого клиента создавть такие задачи, то какой выигрышь от ухода от модели один клиент-один поток?

RTFM smile 

Автор: bsa 27.2.2011, 20:35
Artemon, основное время при работе по сети расходуется на ожидание ответа от удаленной машины. Это может делать как ядро системы, так и приложение. Отличия только в том, какой вызов используется. Есть синхронный, а есть асинхронный. Отличия в том, что если первый ждет завершения выполнения операции, то второй не ждет. При завершении операции приходит определенный сигнал. Вот asio с этим и работает.

Автор: xvr 28.2.2011, 16:54
asio не позволяет выполнять какую то работу параллельно с другой работой, она позволяет выполнять ввод/вывод параллельно с другой работой. Что бы обращение к BD было асинхронным, оно должно быть оформлено в виде отправки запроса через сеть (например запись текста SQL запроса в пайп), и дальнейшего чтения ответа опять же через сеть.

В таком случае asio позволит время от отправки запроса и до получения ответа использовать для обслуживания других клиентов

Автор: boostcoder 28.2.2011, 18:47
Цитата(xvr @  28.2.2011,  16:54 Найти цитируемый пост)
 Что бы обращение к BD было асинхронным, оно должно быть оформлено в виде отправки запроса через сеть

во первых - зачем?
во вторых - а если БД локальная, какой смысл в interprocess-comunication?

Автор: xvr 28.2.2011, 23:07
Цитата(boostcoder @ 28.2.2011,  18:47)
Цитата(xvr @  28.2.2011,  16:54 Найти цитируемый пост)
 Что бы обращение к BD было асинхронным, оно должно быть оформлено в виде отправки запроса через сеть

во первых - зачем?

Это вопрос к ТС, а то он пытается от asio добиться каких то чудес  smile 
Цитата

во вторых - а если БД локальная, какой смысл в interprocess-comunication?
Никакого. Смысл будет, если БД удаленная

Автор: Artemon 1.3.2011, 20:26
Чудес я добиться не пытаюсь, а хочу лишь понять насколько реально сделать сервер на asio, под сервером я НЕ имею ввиду простейшие чаты, эхо серверы и прочее, а серьезный сервер, выполняющий сотни различных команд, делающий сложный выборки, реализующий часть логики клиентского приложения и т.д.

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

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

Автор: boostcoder 1.3.2011, 20:33
Цитата(xvr @  28.2.2011,  23:07 Найти цитируемый пост)
Это вопрос к ТС

я лишь хотет сказать, что задачу выборки из БД, можно выполнить асинхронно, при помощи asio::io_service::post()

Цитата(xvr @  28.2.2011,  23:07 Найти цитируемый пост)
Смысл будет, если БД удаленная

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

Цитата(Artemon @  1.3.2011,  20:26 Найти цитируемый пост)
под сервером я НЕ имею ввиду простейшие чаты, эхо серверы и прочее, а серьезный сервер, выполняющий сотни различных команд, делающий сложный выборки, реализующий часть логики клиентского приложения и т.д.

читать: http://forum.vingrad.ru/index.php?showtopic=323481&view=findpost&p=2306305

Автор: Artemon 1.3.2011, 21:09
Получется так, что каждый запрос клиента заставляет сервер лезть в БД и долго(к примеру 10 секунд) копаться с ней.

Вижу следующий алгоритм работы сервера:

1. Сервер стоит и ждет подключения клиента.
2. Подключается клиент, все ok ресурсов почти не потрачено.
3. Клиент посылает серверу запрос, вот тут есть 2 варианта:
a. В основном потоке сервера обратиться к БД, при этом 10 секунд все остальные клиенты ждут.
b. Создать поток, в котром будет запрос к БД, собственно от чего уходили к тому и пришли.
c. Использовать Post, но опятже он работает в контексте свободного потока.


Можеть я еще какой-то вариант из пункта №3 пропустил ?

Автор: boostcoder 1.3.2011, 21:14
Цитата(Artemon @  1.3.2011,  21:09 Найти цитируемый пост)
Получется так, что каждый запрос клиента заставляет сервер лезть в БД и долго(к примеру 10 секунд) копаться с ней.

все зависит от типа БД, и от того, кто ее проектировал.

Цитата(Artemon @  1.3.2011,  21:09 Найти цитируемый пост)
c. Использовать Post, но опятже он работает в контексте свободного потока.


Можеть я еще какой-то вариант из пункта №3 пропустил ?

а что не так?
возможно вы действительно ожидаете чудес ;)

Автор: Artemon 1.3.2011, 21:20
Цитата(boostcoder @  1.3.2011,  21:14 Найти цитируемый пост)
а что не так?

Похоже что караз таки все так и чудест действительно не получится smile


Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)