Блокируется ли этот актор Scala при создании нового актора в обработчике?

У меня есть следующий фрагмент кода:

actor {
  loop {
     react {
       case SomeEvent =>
         //I want to submit a piece of work to a queue and then send a response 
         //when that is finished. However, I don't want *this* actor to block
         val params = "Some args"
         val f: Future[Any] = myQueue.submitWork( params );
         actor {
           //await here
           val response = f.get
           publisher ! response
         }

     }
  }
}

Насколько я понял, внешний актор не будет блокироваться на f.get, потому что на самом деле это выполняется отдельным актором (тот, который создан внутри обработчика SomeEvent).

Это правильно?


person oxbow_lakes    schedule 05.06.2009    source источник


Ответы (1)


Да, это правильно. Ваш внешний актор просто создаст актор и приостановит его работу (дождитесь его следующего сообщения). Однако будьте очень осторожны с такими вещами. Внутренний актор автоматически запускается в планировщике и обрабатывается потоком. Этот поток заблокирует это будущее (для меня это выглядит как java.util.concurrent.Future). Если вы сделаете это достаточное количество раз, вы можете столкнуться с проблемами голодания, когда все доступные потоки блокируются на фьючерсах. Актер — это, по сути, рабочая очередь, поэтому вместо этого вы должны использовать эту семантику.

Вот версия вашего кода с использованием библиотека актеров Scalaz. Эта библиотека гораздо проще и понятнее, чем стандартные акторы Scala (исходник буквально на полторы страницы). Это также приводит к гораздо более лаконичному коду:

actor {(e: SomeEvent) => promise { ... } to publisher }

Эта версия полностью не блокирует.

person Apocalisp    schedule 05.06.2009
comment
Но если я отправляю работу в очередь и получаю (juc) Future обратно, как я могу избежать блокировки в случае, когда я не контролирую API очереди (т. е. если я не могу повторно реализовать очередь работ, поэтому что издателю выдаются события по завершении работы)? - person oxbow_lakes; 05.06.2009
comment
Можете ли вы отправить произвольный код в рабочую очередь? Если это так, вы можете отправить вычисление с единичным значением, которое заканчивается отправкой сообщения одному из ваших акторов. И просто игнорируйте Future[Unit] - person Apocalisp; 05.06.2009
comment
Я отредактировал вопрос, чтобы было немного понятнее, что именно я вызываю, когда отправляю работу. В основном нет, я не могу отправлять произвольные runnables/callables. Тем не менее, я изначально написал весь код, поэтому, похоже, мне просто нужно внести изменения в API :-) - person oxbow_lakes; 05.06.2009
comment
Если рабочая очередь представляет собой написанный вами Java API, рассмотрите возможность его рефакторинга с учетом «Лучшего будущего»: apocalisp.wordpress.com/2008/09/02/a-better-future - person Apocalisp; 05.06.2009
comment
Кроме того, учтите, что в вашем случае может быть нормально заблокировать. Если эта система не является высококонкурентной или если ничего не будет зависеть от значения в Будущем. - person Apocalisp; 05.06.2009
comment
Он написан на Scala, но я в значительной степени чувствую свой путь, поэтому все еще использую некоторые конструкции juc. Я не нашел отличного ресурса для изучения параллелизма Scala, кроме нескольких простых примеров. Моя основная проблема затрагивается здесь (unlimitednovelty.com/2009 /04/why-i-dont-like-scala.html). Где вы проводите грань между действующими лицами/сообщениями и методами? - person oxbow_lakes; 05.06.2009
comment
По сути, мои рабочие элементы должны ждать, пока какой-то ресурс станет доступным, поэтому я не могу избежать блокировки в какой-то момент. Я также хочу иметь возможность отменить ранее запрошенную часть работы. Задам отдельный вопрос по теме, если вы хотите на него ответить - person oxbow_lakes; 05.06.2009
comment
Вот здесь: stackoverflow.com /вопросы/954882/ - person oxbow_lakes; 05.06.2009