#scala #playframework-2.0 #akka #iterate
#scala #playframework-2.0 #akka #итерация
Вопрос:
Я хочу параллельно обрабатывать несколько задач внутри действия и возвращать любой результат задачи в порядке первого завершения и сразу после его завершения.
Например, если задача A завершается через 5 секунд, задача B завершается через 3 секунды, а задача C завершается через 1 секунду, вывод должен быть «C», «B», «A».
Следующие коды, похоже, выводят неправильный порядок и ожидают завершения всей задачи, прежде чем выводить результат.
def lookup = Action { implicit req =>
val a = Enumerator( Await.result(Promise.timeout("A", 5 seconds), 1 minute))
val b = Enumerator( Await.result(Promise.timeout("B", 3 seconds), 1 minute))
val c = Enumerator( Await.result(Promise.timeout("C", 1 second), 1 minute))
val d = a >- b >- c
Ok.chunked(d amp;> Comet(callback = "console.log"))
}
Комментарии:
1. Каков ваш фактический вариант использования? Этот код выглядит довольно надуманным, поскольку Await.result вложен в перечислитель.
2. @Ryan Я просто хотел смоделировать источники для Enumerator — это несколько заблокированных функций. Похоже
Enumerator(someFunction)
, я подумал, что было проще проиллюстрировать эту проблему.
Ответ №1:
Ваш код нарушен из-за того, как вы используете Await.result
. Строка, которая определяет a
, не завершается до Await.result
тех пор, пока не вернется, и поэтому обещание для b
никогда не начинается до тех пор, пока не закончится одно для a
. Если вы используете что-то вроде:
val a = Enumerator.flatten(Future.firstCompletedOf(List(
Promise.timeout("A", 5 seconds),
Promise.timeout(throw new Exception("A timed out"), 1 minute)
)).map(Enumerator(_)))
Вы получите правильное поведение.
Комментарии:
1. Спасибо, что указали на это, итак, каков обычный шаблон для этого случая — счетчики должны получать источники из разных
def taskX:Future[X]
источников?2.
Enumerator.flatten(future.map(Enumerator(_)))
преобразует фьючерсы в счетчики, с которыми их затем можно комбинировать>-
. Тайм-ауты действительно должны обрабатываться тем, что создает будущее, чтобы оно могло остановить то, что оно делает, когда срабатывает тайм-аут, напримерWSRequestHolder.withRequestTimeout
, см.