Это использование Акторов Scala 2.8. У меня есть длительная работа, которую можно распараллелить. Он состоит из около 650 000 единиц работы. Я разделил его на 2600 различных отдельных подзадач, и для каждой из них я создал нового актера:
actor {
val range = (0L to total by limit)
val latch = new CountDownLatch(range.length)
range.foreach { offset =>
actor {
doExpensiveStuff(offset,limit)
latch.countDown
}
}
latch.await
}
Это работает довольно хорошо, но в целом для выполнения требуется 2 + час. Проблема в том, что тем временем любые другие акторы, которые я создаю для выполнения обычных задач, кажутся голодными из-за начальных 2600 акторов, которые также терпеливо ждут своего времени для запуска в потоке, но ждали дольше, чем любые новые акторы, которые пойдем.
Как я могу избежать этого голода?
Начальные мысли:
ОБНОВЛЕНИЕ
Некоторые люди вообще сомневаются в использовании Актеров, особенно потому, что возможность передачи сообщений не использовалась рабочими. Я предполагал, что Actor - это очень легкая абстракция вокруг ThreadPool на том же уровне производительности или почти на том же уровне производительности, что и при простом кодировании выполнения на основе ThreadPool вручную. Поэтому я написал небольшой тест:
import testing._
import java.util.concurrent._
import actors.Futures._
val count = 100000
val poolSize = 4
val numRuns = 100
val ActorTest = new Benchmark {
def run = {
(1 to count).map(i => future {
i * i
}).foreach(_())
}
}
val ThreadPoolTest = new Benchmark {
def run = {
val queue = new LinkedBlockingQueue[Runnable]
val pool = new ThreadPoolExecutor(
poolSize, poolSize, 1, TimeUnit.SECONDS, queue)
val latch = new CountDownLatch(count)
(1 to count).map(i => pool.execute(new Runnable {
override def run = {
i * i
latch.countDown
}
}))
latch.await
}
}
List(ActorTest,ThreadPoolTest).map { b =>
b.runBenchmark(numRuns).sum.toDouble / numRuns
}
// List[Double] = List(545.45, 44.35)
Я использовал абстракцию Future в ActorTest, чтобы не передавать сообщение обратно другому актору, чтобы сигнализировать о том, что работа выполнена. Я был удивлен, обнаружив, что мой Актерский код был более чем в 10 раз медленнее. Обратите внимание, что я также создал свой ThreadPoolExecutor с начальным размером пула, с которым создается пул акторов по умолчанию.
Оглядываясь назад, кажется, что я, возможно, злоупотреблял абстракцией Actor. Я' m собираюсь изучить возможность использования отдельных пулов потоков для этих отдельных, дорогих и длительных задач.