Повышение производительности Asio однопоточное

Я реализую пользовательский сервер, который должен поддерживать очень большое количество (100 КБ или более) долгоживущих соединений. Сервер просто передает сообщения между сокетами и не выполняет какой-либо серьезной обработки данных. Сообщения небольшие, но многие из них принимаются / отправляются каждую секунду. Сокращение задержки является одной из целей. Я понимаю, что использование нескольких ядер не улучшит производительность, и поэтому я решил запустить сервер в одном потоке, вызвав run_one или же poll методы io_service объект. В любом случае многопоточный сервер будет гораздо сложнее реализовать.

Каковы возможные узкие места? Системные вызовы, пропускная способность, очередь завершения / демультиплексирование событий? Я подозреваю, что для диспетчеризации диспетчеров может потребоваться блокировка (это делается внутри библиотеки asio). Можно ли отключить даже блокировку очереди (или любую другую блокировку) в boost.asio?

РЕДАКТИРОВАТЬ: связанный вопрос. Производительность системного вызова улучшается с несколькими потоками? Мне кажется, что поскольку системные вызовы атомарны / синхронизируются ядром, добавление большего количества потоков не улучшит скорость.

11

Решение

Вы можете прочитать мой вопрос Несколько лет назад я спросил об этом, когда впервые исследовал масштабируемость Boost.Asio при разработке системного программного обеспечения для Blue Gene / Q суперкомпьютер.

Масштабирование до 100 тыс. Или более соединений не должно быть проблемой, хотя вам необходимо знать об очевидных ограничениях ресурсов, таких как максимальное количество дескрипторов открытых файлов. Если вы не читали семенной Бумага C10K, Я предлагаю прочитать это.

После того, как вы реализовали свое приложение, используя один поток и один io_serviceЯ предлагаю исследовать пул потоков, вызывающих io_service::run(), и только потом расследуй пиннинг io_service в конкретный поток и / или процессор. Есть несколько примеров, включенных в документацию Asio для всех трех из этих проектов, и несколько вопросов на ТАК с дополнительной информацией. Имейте в виду, что при вводе нескольких потоков вызывая io_service::run() вам может понадобиться реализовать strands для обеспечения того, чтобы обработчики имели эксклюзивный доступ к общим структурам данных.

16

Другие решения

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

Как правило, узким местом для boost :: asio является то, что Epoll / Kqueue реактор работает в мьютексе. Таким образом, только одна нить выполняет epoll одновременно. Это может снизить производительность в случае, когда у вас есть многопоточный сервер, который обслуживает много-много очень маленьких пакетов. Но, в любом случае, это должно быть быстрее, чем просто простой сервер.

Теперь о твоей задаче. Если вы хотите просто передавать сообщения между соединениями — я думаю, что это многопоточный сервер. Проблема в системных вызовах (recv / send и т. Д.). Инструкция очень легко сделать для процессора, но любой системный вызов — не очень «легкая» операция (все относительно, но относительно других заданий в вашей задаче). Итак, с одним потоком вы получите большие системные вызовы, поэтому я рекомендую использовать многопоточную схему.

Кроме того, вы можете отделить io_service и заставить его работать как «io_service per thread» идиома. Я думаю, что это должно дать лучшую производительность, но у него есть недостаток: если один из io_service получит слишком большую очередь — другие потоки не помогут, поэтому некоторые соединения могут замедляться. С другой стороны, с одним io_service — переполнение очереди может привести к большим накладным расходам блокировки. Все, что вы можете сделать — сделать оба варианта и измерить пропускную способность / задержку. Должно быть не так уж сложно реализовать оба варианта.

9

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector