2015-01-21 2 views
3

Я написал этот метод:Поведение метода Future.sequence SCALA в

import scala.concurrent._ 
import ExecutionContext.Implicits.global 
import scala.util.{ Success, Failure } 

object FuturesSequence extends App { 
    val f1 = future { 
    1 
    } 

    val f2 = future { 
    2 
    } 

    val lf = List(f1, f2) 

    val seq = Future.sequence(lf) 

    seq.onSuccess { 
    case l => println(l) 
    } 
} 

Я ожидал Future.sequence собрать список [будущее] в будущем [Список], а затем ждать каждый фьючерс (f1 и f2 в моем случае) для завершения до вызова onSuccess в будущем [List] seq в моем случае.

Но после многих прогонов этого кода он печатает «Список (1, 2)» только раз в то время, и я не могу понять, почему он не работает должным образом.

+0

Приложение выхода обратного вызова до того, как может быть выполнена. –

+0

Cf. http://stackoverflow.com/questions/16612517/execution-context-without-daemon-threads-for-futures –

+1

Как говорили другие. Контекст исполнения по умолчанию запускает ваши фьючерсы на потоки демона, которые не останавливают запуск JVM. Если это для быстрого теста, проще всего использовать Await.result на seq –

ответ

3

Попробуйте это за один раз,

import scala.concurrent._ 
import java.util.concurrent.Executors 
import scala.util.{ Success, Failure } 

object FuturesSequence extends App { 
    implicit val exec = ExecutionContext.fromExecutor(Executors.newCachedThreadPool) 
    val f1 = future { 
    1 
    } 

    val f2 = future { 
    2 
    } 

    val lf = List(f1, f2) 

    val seq = Future.sequence(lf) 

    seq.onSuccess { 
    case l => println(l) 
    } 
} 

Это всегда будет печатать List(1,2). Причина проста: exec - это ExecutionContext потоков (а не потоки демона), где, как и в вашем примере, ExecutionContext по умолчанию был неявным, взятым из ExecutionContext.Implicits.global, который содержит потоки демона.

Следовательно, будучи демоном, процесс не ждет завершения seq будущего и заканчивается. если на всех seq действительно будет завершено, то он печатает. Но этого не всегда бывает

3

Приложение выходит до того, как будет завершено будущее.

You need to block until the future has completed. Это может быть достигнуто различными способами, в том числе изменение ExecutionContext, инстанцировании новый ThreadPool, Thread.sleep и т.д., или с использованием методов на scala.concurrent.Await

Самый простой способ для вашего кода с помощью Await.ready. Это блокируется на future в течение определенного периода времени. В модифицированном коде ниже приложение ждет 5 секунд перед выходом.

Обратите внимание, что дополнительный импорт scala.concurrent.duration, поэтому мы можем указать время ожидания.

import scala.concurrent._ 
import scala.concurrent.duration._ 
import java.util.concurrent.Executors 
import scala.util.{ Success, Failure } 

object FuturesSequence extends App { 
    val f1 = future { 
    1 
    } 

    val f2 = future { 
    2 
    } 

    val lf = List(f1, f2) 

    val seq = Future.sequence(lf) 

    seq.onSuccess { 
    case l => println(l) 
    } 

    Await.ready(seq, 5 seconds) 
} 

Используя Await.result вместо этого, вы можете пропустить метод onSuccess тоже, как он будет возвращать полученный список к вам.

Пример:

val seq: List[Int] = Await.result(Future.sequence(lf), 5 seconds) 
println(seq) 
Смежные вопросы