люди, запомните!
акторы - не для распараллеливания, а как раз совсем наоборот - для конкурентности
для распараллеливания - аппликативные функторы

автор - _xacid_

акторы осуществляют обмен асинхронными сообщениями между собой и измененяют свои состояния в ответ на эти сообщения. то есть без способности актора изменять свое состояние и возможности обмениваться АСИНХРОННЫМИ сообщениями с другими акторами - нет и вообще никакой собственно модели акторов

аппликативные же функторы сообщениями не обмениваются и состояний своих не меняют :) и аппликативы, в отличие от монад, НЕ ТРЕБУЮТ последовательной композиции - вот благодаря этому они и подходят для параллельной композиции

я могу об акторах и фьючерах (которые нам нужны как аппликативы - чтобы компоновать) сказать только одно - они изоморфны. и, наверное, являют собой какие-нибудь пределы в какой-нибудь алгебре :)

а раз они изоморфны, то в общем случае нет разницы, что использовать. однако это только в общем случае - на практике фьючеры более предпочтительны и следует использовать (по возможности) именно фьючеры

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

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

с фьючерами нет практически вообще никаких проблем - в то время как с акторами проблем просто не оберешься

* * *

что главное - акторы (как и положено объектам) практически никак НЕ КОМПОНУЮТСЯ (сообщения - это не композиция) в то время как фьючеры компонуются идеально и главное - безопасно по типам, в отличие от акторов

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

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

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

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

* * *

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

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

ну если актор упрощает что-нибудь где-нибудь, то это конечно замечательно! но все-таки это не так уж и часто на самом деле бывает, да и то до поры, до времени, а потом начинается кошмар

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

а эти ублюдки создают в таком случае каждому пользователю (и на каждый его отдельный запрос) нового актора и в нем считают (для каждого отдельного пользователя) одну и ту же статистику запросами в базу данных. они считают что акторы - это просто классы-потоки (как сказал чувак - "акторы - это легковесные потоки"). они пишут всю бизнес-логику прямо в акторах, разбивая ее по разным классам-акторам и запускают это всё без какого либо конфигурирования Akka (то есть в пуле потоков по умолчанию и работают все эти акторы в одном и том же пуле все сразу). бизнес-логика предполагает выполнение запросов к базе данных, причем дофига запросов. и к тому же нужно же как то там мап-редюсить - вот они и мап-редюсят вызывая Await на Future который возвращается из актора. получается в итоге что - акторы постоянно блокируют потоки в пуле, в котором исполняются

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

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