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

28

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

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

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

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

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

Один актер обрабатывает сообщения последовательно, потому что идея заключается в том, что можно использовать актора для обеспечения доступа к (в противном случае) общему ресурсу, и никакой другой синхронизации на общем ресурсе не потребуется. Если сообщения могут обрабатываться последовательно, вам нужно будет использовать блокировки внутри ваших акторов, чтобы избежать ошибок синхронизации. Ken Bloom
Я действительно не понимаю, как этот вопрос оправдывает отрицательное мнение. Если я могу прочитать целую главу об актерах в Программировании в Scala и не быть уверенным в ответе, это вполне правильный вопрос. oxbow_lakes

Ваш Ответ

3   ответа
0

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

Это бесполезный ответ. Допустим, у меня есть какой-то актер, который читает события, которые нужно обработать, и отправляет их другому обработчику, который будет обработан. За исключением того, что на самом деле несколько событий могут обрабатываться одновременно, даже если фактический код обработки точно такой же (который я бы поэтому написал в одном месте, то есть в 1 акторе). Как я могу позволить структуре актеров «копировать» (или создавать пул) этих (идентичных) актеров, чтобы я мог наилучшим образом использовать свои программные ресурсы? oxbow_lakes
Я имею в виду «лучшее использование ресурсов моего процессора» oxbow_lakes
Мой ответ был бесполезным, потому что ваш вопрос не был правильно сформулирован. Актер - это процесс, а не кусок кода. Также как объект является экземпляром класса. Вы не спрашивали, как мне создать несколько актеров для обработки нескольких сообщений. Вы хотели знать, как заставить актера обрабатывать несколько сообщений одновременно. Мой ответ был попыткой прояснить то, что я воспринял как ваше недопонимание модели актера. mamboking
Ты не пытался что-то прояснить. Если бы вы разместили содержимое вашего комментария вместо этого, вы бы получили upvote; не отрицательный голос oxbow_lakes
26

аботки нескольких сообщений - наличие одного фронта координатора для группы потребителей. Если вы используете реагировать, то пул потребителей может быть большим, но все равно будет использовать только небольшое количество потоков 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))
Можете ли вы объяснить, что значит Готов? Seun Osewa
Ready в этом примере - это класс case, который действует как передаваемое сообщение. Координатор отправляет сообщение «Готов» потребителю, которое в основном означает «Вы готовы?» и потребитель отвечает готовым сообщением, которое означает «да». Первый потребитель, который ответит, затем передает запро harmanjd
6

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

Похожие вопросы