Занимаюсь сейчас разработкой нового диспетчера для SObjectizer в составе so5extra. Это asio_one_thread диспетчер. Т.е. создается отдельный экземпляр asio::io_context и на отдельной нити для этого экземпляра запускается цикл обработки событий (т.е. дергается метод io_context::run()). Вся обработка событий агентов, привязанных к такому диспетчеру, выполняется только средствами Asio. По сути, собщения на агентов на этом диспетчере доставляются через asio::post.
Нужен такой диспетчер для того, чтобы можно было к io_context привязать одного или нескольких агентов, которые бы посредством Asio выполняли работу с сетью. И при этом вся работа выполнялась бы строго в рамках одной рабочей нити и никуда больше не уходила.
По сути, диспетчер уже готов и осталось его только задокументировать. Поэтому руки дошли до того, чтобы с помощью нового диспетчера повторить штатный пример ping-pong из SObjectizer-а. И получаются интересные результаты замеров времени работы этого примера.
Когда pinger и ponger работают на контекте одной нити (т.е. привязаны к одному io_context-у):
$ time ./target/gcc_7_5_0__x86_64_linux_gnu/release/sample.so_5_extra.disp.asio_one_thread.ping_pong -r 2700000
Configuration: separate dispatchers: no, requests: 2700000
real 0m1,056s
user 0m1,042s
sys 0m0,005s
Т.е. несколько меньше 3M ping-pong/sec, что весьма неплохо.
На штатном one_thread-диспетчере из SObjectizer-а выходит чуть больше 3M msg/sec:
$ time ./target/gcc_7_5_0__x86_64_linux_gnu/release/sample.so_5.ping_pong -r 2700000
Configuration: active objects: no, requests: 2700000
real 0m0,768s
user 0m0,750s
sys 0m0,008s
Самая веселуха начинается когда агентов разносишь на разные нити. В случае штатного one_thread-диспетчера получается:
$ time ./target/gcc_7_5_0__x86_64_linux_gnu/release/sample.so_5.ping_pong -r 2700000 -a
Configuration: active objects: yes, requests: 2700000
real 0m3,479s
user 0m5,092s
sys 0m1,795s
Т.е. порядка 776K ping-pong/sec.
А вот у нового asio_one_thread-диспетчера лучший результат вот такой:
$ time ./target/gcc_7_5_0__x86_64_linux_gnu/release/sample.so_5_extra.disp.asio_one_thread.ping_pong -r 2700000 -s
Configuration: separate dispatchers: yes, requests: 2700000
real 0m18,394s
user 0m11,465s
sys 0m14,112s
Порядка 146K ping-pong/sec или почти в пять раз хуже.
Что еще раз говорит о том, что передача информации между рабочими нитями -- это интересная тема. И если вам в программе нужно обмениваться сообщениями между сущностями, то гораздо лучше, когда эти сущности работают на одном и том же контексте. Ну или если они работают на разных контекстах, то лучше всего передавать информацию скопом, а не разрозненными мелкими сообщениями.
Я придерживаюсь следующих правил. Не надо использовать нити, если вы точно не уверены, что вам это нужно. Выйгрышь в скорости нити дают лишь в случае, если каждая нить работает только со своими данными. Соответственно желательно увеличить период, когда нить работает только со своими данными, и свести к минимому необходимость обмена данными между нитями.
ОтветитьУдалитьНити применяются еще и для того, чтобы разнести разные операции по разным контекстам, дабы они не оказывали влияния друг на друга.
ОтветитьУдалить