Ответ 1
Использовать фьючерсы в Scala 2.10. Они были совместной работой между командой Scala, командой Akka и Twitter, чтобы достичь более стандартизированного будущего API и реализации для использования в рамках фреймворков. Мы только что опубликовали руководство по адресу: http://docs.scala-lang.org/overviews/core/futures.html
Помимо того, что он полностью не блокируется (по умолчанию, хотя мы предоставляем возможность выполнять управляемые операции блокировки) и скомпонован, фьючерсы Scala 2.10 поставляются с неявным пулом потоков для выполнения ваших задач, а также некоторыми утилитами для управлять тайм-аутами.
import scala.concurrent.{future, blocking, Future, Await, ExecutionContext.Implicits.global}
import scala.concurrent.duration._
// Retrieve URLs from somewhere
val urls: List[String] = ...
// Download image (blocking operation)
val imagesFuts: List[Future[...]] = urls.map {
url => future { blocking { download url } }
}
// Do something (display) when complete
val futImages: Future[List[...]] = Future.sequence(imagesFuts)
Await.result(futImages, 10 seconds).foreach(display)
Выше мы сначала импортируем несколько вещей:
-
future
: API для создания будущего. -
blocking
: API для управляемой блокировки. -
future
: будущий объект-компаньон, который содержит ряд полезных методов для коллекций фьючерсов. -
Await
: объект singleton, используемый для блокировки в будущем (передача его результата в текущий поток). -
ExecutionContext.Implicits.global
: пул потоков по умолчанию, пул ForkJoin. -
duration._
: утилиты для управления продолжительностью времени.
imagesFuts
остается в значительной степени таким же, как и то, что вы изначально сделали - единственное отличие здесь в том, что мы используем управляемую блокировку blocking
. Он уведомляет пул потоков о том, что блок кода, который вы передаете ему, содержит длительные или блокирующие операции. Это позволяет пулу временно создавать новых работников, чтобы не допустить, чтобы все рабочие были заблокированы. Это делается для предотвращения голодания (блокирования пула потоков) в блокирующих приложениях. Обратите внимание, что пул потоков также знает, когда код в блоке блокировки блокировки завершен, поэтому он удалит лишний рабочий поток в этой точке, а это означает, что пул будет уменьшаться до ожидаемого.
(Если вы хотите полностью предотвратить создание дополнительных потоков, то вы должны использовать библиотеку AsyncIO, такую как библиотека Java NIO.)
Затем мы используем методы сбора объекта-компаньона Future для преобразования imagesFuts
из List[Future[...]]
в Future[List[...]]
.
Объект Await
заключается в том, как мы можем гарантировать, что display
выполняется в вызывающем потоке - Await.result
просто заставляет текущий поток ждать, пока будущее, которое оно передано, будет завершено. (Это внутреннее использование управляемой блокировки.)