2017-10-10 47 views
0

我使用Redis和Scala。 Redis的任务是future,所以我必须研究未来(线程)。在斯卡拉有什么不同,等待,Thread.sleep和理解?

我发现很多方法来等待future停止。我不知道有什么不同。 AwaitThread.sleepfor的理解有什么区别?

val redisResult1 = redis.set(objectId, value) 
    Await.ready(redisResult1, Duration.Inf) 

    val redisResult2 = redis.set(objectId, value) 
    for { 
    _ <- redisResult2 
    } yield { 
    "end" 
    } 

    val redisResult3 = redis.set(objectId, value) 
    while(redisResult3.isCompleted) Thread.sleep(10) 
+0

理想情况下,你应该避免等待(尽可能地推出)和连锁期货(如在'for'理解中那样)。 – Thilo

+0

如果你想在while循环中轮询,它应该是'while(!isCompleted)'。但最好使用'Await.ready',这是为了这个确切的目的而制作的。 – Thilo

+0

hwan下面有两个貌似好的答案,他们有什么好处? – halfer

回答

1

好吧,让我们从秒示例开始。 考虑下面的代码片段:

import scala.concurrent.Future 
import scala.concurrent.ExecutionContext.Implicits.global 

object Test2{ 
    def main(args:Array[String]):Unit={ 
    val f = Future{Thread.sleep(5000); "i'm done"} 
    val r = for{ 
     _ <- f 
    } yield "completed" 
    println(r) 
    } 
} 

猜猜它会打印?它打印

Future(<not completed>) 

Process finished with exit code 0 

所以其实这里你是不是等待将来完成时,您只需映射第一未来的结果,并返回它作为其他未来的第一个完成后,将完成。正如你所看到的,该计划不会等到最终的未来完成并正好退出。 for对期货的理解是用于映射和平滑映射它们的糖语法。

Await.resultAwait.ready真的等待未来完成(或超时通过)。但是它们是以阻塞的方式实现的,所以你使用这些方法的线程将被阻塞。这并不总是很糟糕,有时可能会有所帮助。例如。在小测试程序或REPL会话中,您最终将未来计算的结果输出到控制台,或者例如在无论如何需要等待结果并且在等待测试时无需执行测试的情况下。

另一种看到你导致这样的小程序的方法是使用scala.io.StdIn.readLine(),这样主线程就会挂起而不会退出。考虑其中说明了这以下,也为您提供了一个更多附加的方式来等待将来完成:

object Test2{ 
    def main(args:Array[String]):Unit={ 
    val f = Future{Thread.sleep(5000); "i'm done"} 
    f foreach (println(_)) 

    scala.io.StdIn.readLine() 
    } 

} 

运行它,你会看到该程序不会退出,打印的未来和退出的结果,那么只有在您按下ENTER键后。

foreach应用于未来是添加onComplete侦听器的快捷方式。非常方便的一个。

至于如果未来完成while循环不断地检查 - 我认为这可能是等待,因为它会继续在主线程忙,浪费更多的空闲CPU电源不是依靠高效地实现Await.result最糟糕的方式。阻碍其他事情也可能是高效率和低效率的。

为了理解所有这些有未来的东西,你需要清楚地认识到,未来的实际执行不会发生在你发起它的同一个线程中。在我们所有的例子中,我们只是在主线程中定义了未来,然后在导入的执行上下文中的一个线程中执行了它。

1

惯用方法是不阻止结果。相反,你应该使用地图/理解和类似的东西来链接期货。

对于flatMaps,maps和withFilters而言,理解仅仅是语法糖,具体取决于您如何使用它。

这不仅是尽可能无阻塞,但它允许您编写“快乐的道路”,而不是尽可能晚地处理故障。

像Play这样的许多框架可以让您永远不会阻止未来完成并允许您将Futures返回给调用者,并且Framework将为您处理它。

如果你必须处理展开的未来,你可能想使用onComplete

退房The Neophytes Guide to Scala对于学习这个东西一个很好的教程。