Подтвердить что ты не робот

Scala - фьючерсы и concurrency

Я пытаюсь понять фьючерсы Scala, исходящие из фона Java: я понимаю, что вы можете написать:

val f = Future {   ...    }

то у меня есть два вопроса:

  • Как планируется это будущее? Автоматически?
  • Какой планировщик будет использовать? В Java вы должны использовать исполнителя, который может быть пулом потоков и т.д.

Кроме того, как я могу достичь scheduledFuture, который выполняется после определенной временной задержки? Благодаря

4b9b3361

Ответ 1

Блок Future { ... } - это синтаксический сахар для вызова Future.apply (как я уверен, вы знаете Maciej), передавая в блок кода как первый аргумент.

Глядя на docs для этого метода, вы можете видеть, что он принимает неявный ExecutionContext - и именно этот контекст определяет, как он будет выполнен. Таким образом, чтобы ответить на ваш второй вопрос, будущее будет выполняться тем, что ExecutionContext находится в неявной области (и, конечно, если это неоднозначно, это ошибка времени компиляции).

Во многих случаях это будет один из import ExecutionContext.Implicits.global, который может быть изменен с помощью свойств системы, но по умолчанию использует ThreadPoolExecutor с одним потоком на процессорное ядро.

Однако планирование - это другое дело. Для некоторых случаев использования вы можете предоставить свой собственный ExecutionContext, который всегда применял ту же самую задержку перед выполнением. Но если вы хотите, чтобы задержка была контролируемой с сайта вызова, то, конечно, вы не можете использовать Future.apply, так как нет параметров для связи, как это должно быть запланировано. В этом случае я предлагаю отправлять задания непосредственно запланированному исполнителю.

Ответ 2

Анджей ответ уже охватывает большую часть земли в вашем вопросе. Стоит упомянуть, что Scala "неявный" контекст выполнения (import scala.concurrent.ExecutionContext.Implicits._) буквально равен java.util.concurrent.Executor, а вся концепция ExecutionContext - очень тонкая оболочка, но тесно связана с каркасом исполнителей Java.

Для достижения чего-то похожего на запланированные фьючерсы, как указывает Маурицио, вам придется использовать promises и любой механизм планирования третьей стороны.

Не имея общего механизма для этого встроенного в фьючерсы Scala 2.10, жаль, но ничего смертельного.

Обещание - это дескриптор для асинхронного вычисления. Вы создаете один (предполагая ExecutionContext в области), вызывая val p = Promise[Int](). Мы просто пообещали целое число. Клиенты могут получить будущее, которое зависит от выполняемого обещания, просто позвонив p.future, который является всего лишь Scala будущим.
Выполнение обещания - это просто вызов p.successful(3), и в этот момент будущее будет завершено.

Play 2.x решает планирование с помощью promises и простого старого таймера Java 1.4.
Здесь - ссылка на источник ссылки.

Давайте также взглянем на источник здесь:

object Promise {
  private val timer = new java.util.Timer()

  def timeout[A](message: => A, duration: Long, unit: TimeUnit = TimeUnit.MILLISECONDS)
                (implicit ec: ExecutionContext): Future[A] = {
    val p = Promise[A]()
    timer.schedule(new java.util.TimerTask {
      def run() {
        p.completeWith(Future(message)(ec))
      }
    }, unit.toMillis(duration))
    p.future
  }
}

Затем это можно использовать так:

val future3 = Promise.timeout(3, 10000) // will complete after 10 seconds

Обратите внимание, что это намного лучше, чем подключить Thread.sleep(10000) к вашему коду, который заблокирует ваш поток и заставит контекстный переключатель.

Также стоит отметить в этом примере val p = Promise... в начале функции и p.future в конце. Это общий шаблон при работе с promises. Предположим, что эта функция делает некоторые обещания клиенту и запускает асинхронное вычисление для его выполнения.

Посмотрите здесь для получения дополнительной информации о Scala promises. Обратите внимание, что они используют строчный future метод из объекта пакета concurrent вместо Future.apply. Первый просто делегирует последнее. Лично я предпочитаю строчный future.