Хорошо, это может быть довольно глупый вопрос, но в чем преимущество использования параллельных коллекций в рамках актера? То есть, если я имею дело только с одним сообщением за раз от почтового ящика актера, есть ли необходимость в параллельной коллекции? Являются ли параллельные коллекции и акторы взаимоисключающими? Что такое прецедент, который будет включать оба?
Параллельные коллекции в Scala 2.9 и актеры
Ответ 1
Они решают разные проблемы. Актеры умеют решать задачи параллельные задачи. В то время как параллельные коллекции хорошо подходят для решения параллельных задач данных. Я не думаю, что они взаимоисключающие - вы можете использовать параллельные коллекции в актерах и параллельные коллекции, содержащие актеров.
Изменить - быстрый тест: Даже что-то простое, например, цикл уведомлений актера.
В следующем коде мы регистрируем миллион участников с реестром актеров, который должен уведомить об этом событие.
Непараллельный цикл уведомлений (registry foreach {}
) занимает в среднем 2,8 секунды на моей машине (4-ядерный 2,5 ГГц ноутбук).
Когда используется цикл параллельного сбора (registry.par.foreach {}
), он занимает 1,2 секунды и использует все четыре ядра.
import actors.Actor
case class Register(actor: Actor)
case class Unregister(actor: Actor)
case class Message( contents: String )
object ActorRegistry extends Actor{
var registry: Set[Actor] = Set.empty
def act() {
loop{
react{
case reg: Register => register( reg.actor )
case unreg: Unregister => unregister( unreg.actor )
case message: Message => fire( message )
}
}
}
def register(reg: Actor) { registry += reg }
def unregister(unreg: Actor) { registry -= unreg }
def fire(msg: Message){
val starttime = System.currentTimeMillis()
registry.par.foreach { client => client ! msg } //swap registry foreach for single th
val endtime = System.currentTimeMillis()
println("elapsed: " + (endtime - starttime) + " ms")
}
}
class Client(id: Long) extends Actor{
var lastmsg = ""
def act() {
loop{
react{
case msg: Message => got(msg.contents)
}
}
}
def got(msg: String) {
lastmsg = msg
}
}
object Main extends App {
ActorRegistry.start
for (i <- 1 to 1000000) {
var client = new Client(i)
client.start
ActorRegistry ! Register( client )
}
ActorRegistry ! Message("One")
Thread.sleep(6000)
ActorRegistry ! Message("Two")
Thread.sleep(6000)
ActorRegistry ! Message("Three")
}
Ответ 2
Библиотека актеров в Scala является лишь одним из вариантов, подходит для concurrency, среди многих (потоки и блокировки, STM, фьючерсы /promises), и она не должна использоваться для всех видов проблем, или быть совместимым со всем (хотя актеры и STM могли бы неплохо объединиться). В некоторых случаях создание группы участников (работников + супервизора) или явное разделение задачи на части, чтобы подавать их в пул fork-join, является слишком громоздким, и это просто способ вызова .par
on существующую коллекцию, которую вы уже используете, и просто проходите ее параллельно, получая преимущество в производительности почти бесплатно (с точки зрения настройки).
В целом, актеры и параллельные коллекции - это разные аспекты проблемы - актеры представляют собой парадигму concurrency, в то время как параллельные коллекции - это просто полезный инструмент, который следует рассматривать не как альтернативу concurrency, а скорее как добавление набора инструментов коллекций.