boost::asio проблема многопоточности

У меня есть сервер, использующий boost::asio, который я хочу сделать многопоточным.

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

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

Однако я не уверен, как это сделать. Я рассматривал идею предоставления каждому компоненту собственного io_service, чтобы он мог использовать любые потоки, которые ему нужны, однако область сокетов привязана к io_service, и я не уверен, как затем переместить клиентский сокет из одного компонента в другой.


person Fire Lancer    schedule 08.12.2009    source источник
comment
Win32 или UNIX или попытка быть переносимой?   -  person Will    schedule 08.12.2009
comment
Должен быть переносимым, в настоящее время Win32, но весьма вероятно, что мы переключимся на Linux, как только некоторые другие вещи на сервере будут перенесены.   -  person Fire Lancer    schedule 08.12.2009


Ответы (2)


Вы можете решить эту проблему с помощью asio::io_service::strand. Создайте пул потоков для io_service как обычно. После того, как вы установили соединение с клиентом, с этого момента оберните все асинхронные вызовы расширением io_service::strand. Одна прядь на клиента. По сути, это гарантирует, что с точки зрения клиента он является однопоточным.

person deft_code    schedule 21.12.2009

Во-первых, я бы посоветовал вместо этого рассмотреть многопроцессный подход; это очень простая, простая в осмыслении и отладке, а также легко масштабируемая архитектура.

Дизайн сервера, который можно масштабировать по горизонтали — несколько экземпляров сервера, состояние внутри каждого из которых не нужно разделять между серверами (например, общее состояние может находиться в общей базе данных (SQL, Волдеморт (постоянный) или Redis (устанавливает и списки - очень здорово, я действительно в восторге от постоянной версии), memcached (ненадежно) или что-то подобное) - легче масштабируется.

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

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

Но в конечном счете, как только вы достигнете насыщения, для масштабирования идеи области вам понадобятся более быстрые ядра, а не больше. Вот интересный монолог одного из наших хостов. об этом.

person Will    schedule 08.12.2009
comment
Дело в том, что в отличие от обычного сервера (я бы так написал), эта система работает вокруг группы клиентов (максимум 50 в крайнем случае), все они работают с одним битом данных (так сказать, с областью), поэтому Причина, по которой мне нужен только один поток на область, чтобы этим 50 клиентам никогда не приходилось устанавливать блокировки, а вместо этого они автоматически обрабатывались одним потоком по одному. - person Fire Lancer; 08.12.2009
comment
Файлового ввода-вывода очень мало, большая его часть будет записываться, что легко сделать асинхронным, используя систему сообщений и отдельный поток записи. - person Fire Lancer; 08.12.2009
comment
На самом деле я сейчас делаю сервер с однопоточным асинхронным дизайном; Иногда мне нужно выполнять тяжелую работу, и когда я это делаю, я fork/execv делаю это и считываю результаты через канал (что я могу сделать с моим основным циклом событий, как если бы это было внешнее соединение) - person Will; 08.12.2009