我正在参加Coursera的Reactive编程课程,当我做其中一项任务时,我遇到了一些奇怪的东西.无论如何,我通过这个扩展为Future Companion对象添加了一些方法
implicit class FutureCompanionOps[T](val f: Future.type) extends AnyVal { /** Returns a future that is always completed with `value`. */ def always[T](value: T): Future[T] = Future(value) /** Returns a future that is never completed. * * This future may be useful when testing if timeout logic works correctly. */ def never[T]: Future[T] = Promise().future /** Given a list of futures `fs`, returns the future holding the list of values of all the futures from `fs`. * The returned future is completed only once all of the futures in `fs` have been completed. * The values in the list are in the same order as corresponding futures `fs`. * If any of the futures `fs` fails, the resulting future also fails. */ def all[T](fs: List[Future[T]]): Future[List[T]] = { val resPr = Promise[List[T]]() def function( in: List[Future[T]], fxs:Future[List[T]] ): Future[List[T]] = { if(in.isEmpty) fxs else function( in.tail, for { i <- in.head ; xs <- fxs } yield { i :: xs } ) } function( fs, resPr.success(Nil).future ) } }
然后我在Eclipse中的Scala WorkSheet上写了这个
object TestSheet { val tempPr = Promise[Boolean]() val anotherFuLs = List( Future.always(true), Future.always(false), tempPr.future ) //> anotherFuLs : List[scala.concurrent.Future[Boolean]] = List(scala.concurren //| t.impl.Promise$DefaultPromise@a19b1de, scala.concurrent.impl.Promise$Default //| Promise@1cec6b00, scala.concurrent.impl.Promise$DefaultPromise@625dcec6) val crapFut = Future.all(anotherFuLs) //> crapFut : scala.concurrent.Future[List[Boolean]] = scala.concurrent.impl.Pr //| omise$DefaultPromise@6564dbd5 crapFut.isCompleted //> res3: Boolean = false tempPr.success(false) //> res4: nodescala.TestSheet.tempPr.type = scala.concurrent.impl.Promise$Defaul //| tPromise@625dcec6 crapFut.isCompleted //> res5: Boolean = true crapFut onComplete { case Success(ls) => println( ls ) case Failure(e) => println( "Failed with Exception " + e ) } }
无论我怎么做都不能让Scala工作表打印出结果列表的值.但是,当我编写单元测试并运行scala测试时,我在比较最终结果列表时没有问题.在使用异步内容时,这是scala工作表中的错误吗?
这是单元测试
test("A composed future with all should complete when all futures complete") { val tempPr = Promise[Boolean]() val lsFu = List( Future.always(true), Future.always(false), tempPr.future ); val fuL = Future.all( lsFu ) fuL onComplete { case Success(ls) => println( "This got done" ); assert( ls === List( true, false, true ), "I should get back the expected List" ) case Failure(ex) => assert( false, "Failed with Exception " + ex ) } assert( fuL.isCompleted === false, "The resulting Future should not be complete when the depending futures are still pending" ) tempPr.success(true) }
Dylan.. 8
看起来问题是运行工作表代码的主线程在onComplete
处理程序运行之前结束.
Scala的默认ExecutionContext
值实际上是一个充满守护程序线程的线程池.在此上下文中的"守护进程"意味着即使该线程忙于执行某些操作,也不会阻止JVM在所有非守护程序线程完成时关闭.在您的情况下,主线程可能是程序中唯一的非守护程序线程.
调用onComplete
Future将使得隐式提供的ExecutionContext将在Future完成时执行您的处理程序.这意味着处理程序在守护程序线程上运行.因为这onComplete
是你在main方法中做的最后一件事,所以JVM只是在ExecutionContext运行处理程序之前完成.
通常情况下,这不是什么大问题.在像Web服务器这样的场景中,您的JVM将启动并运行很长时间.对于您的用例,我建议使用其中一种方法阻止Future完成scala.concurrent.Await
.这样,您可以在main方法中将完成逻辑作为主线程的一部分运行.
看起来问题是运行工作表代码的主线程在onComplete
处理程序运行之前结束.
Scala的默认ExecutionContext
值实际上是一个充满守护程序线程的线程池.在此上下文中的"守护进程"意味着即使该线程忙于执行某些操作,也不会阻止JVM在所有非守护程序线程完成时关闭.在您的情况下,主线程可能是程序中唯一的非守护程序线程.
调用onComplete
Future将使得隐式提供的ExecutionContext将在Future完成时执行您的处理程序.这意味着处理程序在守护程序线程上运行.因为这onComplete
是你在main方法中做的最后一件事,所以JVM只是在ExecutionContext运行处理程序之前完成.
通常情况下,这不是什么大问题.在像Web服务器这样的场景中,您的JVM将启动并运行很长时间.对于您的用例,我建议使用其中一种方法阻止Future完成scala.concurrent.Await
.这样,您可以在main方法中将完成逻辑作为主线程的一部分运行.