Pull to refresh

Comments 10

Выглядит впечатляюще. Только появились вопросы:
1) Что с накладными расходами? Насколько медленне [или быстрее] отправить сообщение агенту, чем захватить мьютекс и вызывать метод некоторого объекта?
2) Я правильно понял, что ответить на сообщение можно только отправив сообщение отправителю?
3) Предполагается, что все агенты "живут" в рамках одного процесса? Можно ли отправить сообщение агенту из другого процесса? А тому, который на другом компьютере?

Отвечу на каждый из вопросов в отдельном комментарии, если позволите.

1) Что с накладными расходами? Насколько медленне [или быстрее] отправить сообщение агенту, чем захватить мьютекс и вызывать метод некоторого объекта?

Накладные расходы сильно зависят от сценариев использования и от того, на каких контекстах работают взаимодействующие агенты. Например, в синтетических бенчмарках разница между простым ping-pong-ом между двумя агентами, работающими на разных нитях и на одной и той же нити, может различаться в разы: от 2M msg/sec при обмене сообщениями между разными нитями до 8-9M msg/sec при работе на одной и той же нити. Причем ping-pong — это достаточно суровый сценарий, т.к. там перед посылкой следующего сообщения нужно дождаться ответа на предыдущее. Могут быть сценарии, где сообщения поступают к агентам пачками, там можно и еще большие числа получить (вот, например).

В принципе, мутекс (а тем более спинлок) с последующим вызовом метода объекта должны быть быстрее. Но когда у вас задача не настолько сложная, чтобы запутаться в мутексах, то вам и инструменты вроде SObjectizer не нужны. А когда настолько сложная, что возня с мутексами сильно замедляет саму разработку, то вы упрощаете себе жизнь за счет асинхронного взаимодействия, но ценой увеличения накладных расходов.
Но и здесь все не так однозначно, т.к. на мутексах вполне можно получить голодание рабочих нитей, когда они взаимно блокируются и ждут какого-то одного мутекса.
2) Я правильно понял, что ответить на сообщение можно только отправив сообщение отправителю?

Есть еще и такой механизм, как синхронное взаимодействие. Агент-отправитель вместо send-а делает вызов request_value, при выполнении которого агент-отправитель блокируется. Агент-получатель получает сообщение обычным образом, как асинхронное, а возвращенное из обработчика значение будет возвращено агенту-отправителю как результат request_value. Будет что-то вроде:
class request_processor : public so_5::agent_t // Агент-получатель.
  ...
  some_result on_request(const some_request & msg ) { // обработчик события.
    ...
    return some_result(...);
  }
};
...
auto result = so_5::request_value< some_result, some_request >(
    request_processor_mbox, // Кому отсылается запрос.
    std::chrono::seconds(10), // Ждать ответа не более 10sec.
    ...); // Параметры для конструктора some_request.

Но этот способ не рекомендуется использовать без особой на то необходимости, т.к. здесь есть ряд ограничений и возможность запросто поймать дедлок.
3) Предполагается, что все агенты «живут» в рамках одного процесса?

Да. Только внутри одного процесса.

Можно ли отправить сообщение агенту из другого процесса? А тому, который на другом компьютере?

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

Этот момент в статье подчеркивается.
Спасибо за ответы! Теперь я составил более-менее, понимание того, что это такое.
Вообще говоря, есть три типа concurrency: 1) на асинхронных агентах; 2) на конкурентных коллекциях; 3) на разделяемых данных. SObjectizer реализует первый тип, OpenMP и TBB — второй, а мьютексы и семафоры — это отдельный третий тип. Некорректно говорить так, что, мол, это удобный инструмент для преодоления сложностей, связанных с мьютексами и семафорами. Параллелизм на асинхронных агентах и параллелизм на мьютексах не связаны между собой отношением «лучше/хуже». Это два принципиально разных подхода к проблеме. Они отличаются друг о друга не меньше, чем каждый из них отличается от массового параллелизма, реализуемого в OpenMP.
Параллелизм на асинхронных агентах и параллелизм на мьютексах не связаны между собой отношением «лучше/хуже».

Речь не о том, лучше или хуже. А о «проще» или «сложнее». Чем больше разделяемых данных и чем больше синхронизирующих их объектов (мутексов и условных переменных), тем сложнее все это удерживать в голове, тем больше вероятность ошибки. Асинхронное взаимодействие уменьшает эту сложность. Хотя платить приходится другими вещами.
Я именно об этом и говорю. Отношение «проще/сложнее» — это проекция отношения «лучше/хуже» на шкалу, где простота лучше сложности.

Асинхроные агенты и мьютексы предназначены для решения задач разного типа. И эти типы задач отличаются не количеством разделяемых данных и синхронизирующихся объектов, а силой/интенсивностью связи между взаимодействующими объектами. Слабосвязанные объекты делаются на акторах/агентах, сильносвязанные синхронизируются через мьютексы. Типовой пример сильносвязанного взаимодействия — это СУБД. При попытке сделать многопользовательскую СУБД на асинхронных агентах вы гораздо быстрее запутаетесь в логике обмена сообщениями, чем в старых-добрых мьютексах. Причём чем больше у вас будет таблиц, связей между ними и параллельных пользователей, тем быстрее вы запутаетесь в потоке сообщений о создании, изменении, удалении отдельных записей. По сути, БД — это один большой shared state. Поэтому здесь подойдут только мьютексы, только транзакции, только хардкор…
Думаю, что даже на вопрос использования акторов в реализации СУБД есть разные взгляды:
http://highscalability.com/blog/2013/11/25/how-to-make-an-infinitely-scalable-relational-database-manag.html
http://hrcak.srce.hr/file/105743

Кроме того, спорить на тему теоретической между разными подходами к concurrent computing не интересно. На практике используются инструменты. Один из них описан здесь. Использовать его для конкретной задачи или нет — это уже выбор конкретной проектной команды.
А спорить и не нужно. Гербушка Саттер подробно описал все три типа параллелизма, которые существуют теоретически, в своей программной статье ещё 10 лет назад: http://www.drdobbs.com/parallel/the-pillars-of-concurrency/200001985?pgno=1
С тех пор ничего не изменилось. И я же ведь ничего не имею против удобного инструмента для использования модели асинхронных агентов. Просто не надо смешивать эту модель с её теоретической противоположностью с целью показать преимущества инструмента, предназначенного для одной модели, на контрасте с инструментами другой. Разумеется, при таком сравнении преимущества будут налицо. Только это как раз неинтересно. Интересно сравнивать сопоставимые вещи, а не совсем разные.
Sign up to leave a comment.

Articles