Когда создаются темы для реакции актера Scala? - PullRequest
8 голосов
/ 06 октября 2009

Прочитав об использовании react в актерах в Scala, я подумал, что react будет использовать тот же поток, поскольку не было нескольких react ожидающих. Кажется, это не так.

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

class SleepyReactor extends Actor {
    def act() {
        loop {
            react {
                case x => {
                    println("reacting to %s on thread %s".format(x, Thread.currentThread.getName))
                    Thread.sleep(1000)
                    println("done with " + x)
                }
            }
        }
    }
}
val sleepyOne = new SleepyReactor
sleepyOne.start
sleepyOne ! "first" // runs on thread-5

// wait until completion

sleepyOne ! "second" // runs on thread-3

Может кто-нибудь объяснить, почему эти react работают в разных потоках и когда создается новый поток для актера с react?

Я где-то читал react основан на событиях, и я понял, что это означает, что «реагирующие акторы» разделяют поток, и если один «реагирует», другие «реагирующие актеры» будут стоять в очереди, пока не будет выполнено первое. Теперь я думаю, что я не прав. Как это работает и чем оно отличается от получения?

Ответы [ 4 ]

9 голосов
/ 07 октября 2009

Это правда, что для действующего субъекта, основанного на событиях, его реагирующий код выполняется в том же потоке, что и код отправки сообщения.

Но в Scala, поскольку нежелательно блокировать поток, когда субъект вызывает блокирующую операцию внутри своего кода реакции, и объединять акторов, основанных на событиях и потоках (с возможностью их составления), оба типа акторов используют тот же пул потоков, но субъекты, основанные на потоках, получают свои собственные потоки, тогда как субъекты, основанные на событиях, совместно используют потоки на основе очереди задач. Для получения подробной информации, смотрите Актеры, которые объединяют потоки и события Филиппом Халлером и Мартином Одерским

5 голосов
/ 08 октября 2009

Не предполагайте отдельный поток для каждого актера. Механизм Scala создает пул рабочих потоков и увеличивает этот пул только в том случае, если размер «заблокированных» субъектов превышает размер пула. Когда ваш актер вызывает receive, он находится в заблокированном состоянии, пока не получит свое сообщение.

4 голосов
/ 29 октября 2011

Чтобы увидеть эффект, описанный в предыдущих ответах, вам нужно создать более двух потоков. Этот пример программы генерирует 100 потоков с получением и 100 потоков с реагированием.

Когда вы запустите его, вы увидите, что каждый принимающий актор занимает поток, а реагирующий - небольшое количество потоков. (Это легче увидеть, когда вы сортируете вывод.)

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

class ReactActor extends Actor {
  def act {
    loop {
      react {
        case 'Hello => println("React: " + Thread.currentThread)
      }
    }
  }
}

class ReceiveActor extends Actor {
  def act {
    while (true) {
      receive {
        case 'Hello => println("Receive: " + Thread.currentThread)
      }
    }
  }
}

object Main {
  def main(args: Array[String]) {
    val count = 100
    val as = new Array[Actor](2 * count)
    for (i <- 0 until count) {
      as(i) = new ReactActor 
      as(count + i) = new ReceiveActor
    } 
    for (a <- as) a.start()
    actor {
      println(Thread.currentThread)
      for (a <- as) a ! 'Hello
    }
  }
}

Сортированный вывод при обычном запуске программы:

Thread[Thread-102,5,main]
React: Thread[Thread-102,5,main]
React: Thread[Thread-102,5,main]
React: Thread[Thread-102,5,main]
...
React: Thread[Thread-102,5,main]
React: Thread[Thread-103,5,main]
React: Thread[Thread-103,5,main]
...
React: Thread[Thread-103,5,main]
React: Thread[Thread-104,5,main]
React: Thread[Thread-104,5,main]
React: Thread[Thread-104,5,main]
...
React: Thread[Thread-104,5,main]
React: Thread[Thread-105,5,main]
React: Thread[Thread-105,5,main]
React: Thread[Thread-105,5,main]
...
React: Thread[Thread-105,5,main]
Receive: Thread[Thread-1,5,main]
Receive: Thread[Thread-10,5,main]
Receive: Thread[Thread-100,5,main]
Receive: Thread[Thread-101,5,main]
Receive: Thread[Thread-11,5,main]
Receive: Thread[Thread-12,5,main]
Receive: Thread[Thread-13,5,main]
Receive: Thread[Thread-14,5,main]
Receive: Thread[Thread-15,5,main]
Receive: Thread[Thread-16,5,main]
Receive: Thread[Thread-17,5,main]
Receive: Thread[Thread-18,5,main]
Receive: Thread[Thread-19,5,main]
Receive: Thread[Thread-2,5,main]
Receive: Thread[Thread-20,5,main]
Receive: Thread[Thread-21,5,main]
...
3 голосов
/ 06 октября 2009

Библиотека планировщика использует пул потоков для управления исполнением актеров. Я не знаю специфики используемой логики, но для меня было бы естественным ожидать:

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...