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

StackOverflow https://stackoverflow.com/questions/1007010

  •  06-07-2019
  •  | 
  •  

Вопрос

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

  

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

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

<Ол>
  • Если предположить, что актер может обрабатывать несколько сообщений одновременно, как я могу заставить актера обрабатывать сообщения по 1 за раз (если это то, что я хочу сделать)? (используя receive ?)
  • Предполагая, что субъект обрабатывает сообщения по одному, как лучше всего реализовать субъект, который на самом деле может обрабатывать сообщения одновременно
  • edit: выполнение небольшого тестирования, кажется, подтверждает, что я ошибаюсь, и что актеры действительно последовательны. Так что это вопрос № 2, на который мне нужно ответить

    Это было полезно?

    Решение

    Актеры обрабатывают одно сообщение за раз. Классический шаблон для обработки нескольких сообщений - наличие одного фронта координатора для группы потребителей. Если вы используете реагировать, то пул потребителей может быть большим, но все равно будет использовать только небольшое количество потоков 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's not doing anything with the results or telling the coordinator to stop
    for (i <- 0 to 1000) coordinator ! Request(self, i.toString)
    

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

    В зависимости от того, что вы делаете, вам может быть лучше подано с Scala's Futures. Например, если вам не нужны актеры, тогда все вышеперечисленные механизмы можно записать как

    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))
    

    Другие советы

    Я думаю, что ответ таков: 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
            }
          }
        }
      }
    

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

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top