Подтвердить что ты не робот

Могут ли участники Scala обрабатывать несколько сообщений одновременно?

Ответ на недавний мой вопрос показал, что актер обрабатывал свои сообщения по одному за раз. Это правда? Я ничего не вижу, что явно говорит об этом (в Программе в Scala), который содержит следующий фрагмент (стр. 593)

Если [метод react] находит сообщение, которое может быть обработано, [он] планирует запланировать обработку этого сообщения для последующего выполнения и выбросить исключение

(Подчеркните мое собственное). Два связанных (и взаимоисключающих) вопроса:

  • Предполагая, что актер может обрабатывать несколько сообщений одновременно, как я могу заставить актера обрабатывать сообщения 1 за раз (если это то, что я хочу сделать)? (используя receive?)
  • Предполагая, что актер обрабатывает сообщения по одному за раз, как мне лучше всего реализовать актера, который на самом деле мог обрабатывать сообщения одновременно.

edit: сделать немного тестирования, похоже, подтверждает, что я ошибаюсь и что актеры действительно последовательны. Итак, это вопрос №2, который мне нужно ответить

4b9b3361

Ответ 1

Актеры обрабатывают одно сообщение за раз. Классический образец обработки нескольких сообщений состоит в том, чтобы иметь одного координатора актера перед пулом потребителей. Если вы используете реакцию, то пул потребителей может быть большим, но будет использовать только небольшое количество потоков JVM. Вот пример, когда я создаю пул из 10 потребителей и один координатор для них.

import scala.actors.Actor
import scala.actors.Actor._

case class Request(sender : Actor, payload : String)
case class Ready(sender : Actor)
case class Result(result : String)
case object Stop

def consumer(n : Int) = actor {
  loop {
    react {
      case Ready(sender) => 
        sender ! Ready(self)
      case Request(sender, payload) =>
        println("request to consumer " + n + " with " + payload)
        // some silly computation so the process takes awhile
        val result = ((payload + payload + payload) map {case '0' => 'X'; case '1' => "-"; case c => c}).mkString
        sender ! Result(result)
        println("consumer " + n + " is done processing " + result )
      case Stop => exit
    }
  }
}

// a pool of 10 consumers
val consumers = for (n <- 0 to 10) yield consumer(n)

val coordinator = actor {
  loop {
     react {
        case msg @ Request(sender, payload) =>
           consumers foreach {_ ! Ready(self)}
           react {
              // send the request to the first available consumer
              case Ready(consumer) => consumer ! msg
           }
         case Stop => 
           consumers foreach {_ ! Stop} 
           exit
     }
  }
}

// a little test loop - note that it not doing anything with the results or telling the coordinator to stop
for (i <- 0 to 1000) coordinator ! Request(self, i.toString)

Этот код проверяет, какой потребитель доступен, и отправляет запрос этому потребителю. Альтернативы - просто случайным образом назначать потребителям или использовать планировщик с циклическим распределением.

В зависимости от того, что вы делаете, вам лучше работать с фьючерсами Scala. Например, если вам действительно не нужны актеры, то все вышеупомянутое оборудование можно записать как

import scala.actors.Futures._

def transform(payload : String) = {      
  val result = ((payload + payload + payload) map {case '0' => 'X'; case '1' => "-"; case c => c}).mkString
  println("transformed " + payload + " to " + result )
  result
}

val results = for (i <- 0 to 1000) yield future(transform(i.toString))

Ответ 2

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

val actor_ = actor {

  loop {
    react {
      case msg =>
        //create a new actor to execute the work. The framework can then 
        //manage the resources effectively
        actor {
          //do work here
        }
      }
    }
  }

Ответ 3

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

Ответ 4

Вы можете попробовать использовать концепции Futures. Пожалуйста, сохраните все эти сообщения, используя Futures, а затем попробуйте обработать их все.