zoukankan      html  css  js  c++  java
  • Scala之Future

    一、简介

    Future提供了一套高效便捷的非阻塞并行操作管理方案。其基本思想很简单,所谓Future,指的是一类占位符对象,用于指代某些尚未完成的计算的结果。一般来说,由Future指代的计算都是并行执行的,计算完毕后可另行获取相关计算结果。以这种方式组织并行任务,便可以写出高效、异步、非阻塞的并行代码。

    所谓Future,是一种用于指代某个尚未就绪的值的对象。而这个值,往往是某个计算过程的结果:

    (1)若该计算过程尚未完成,我们就说该Future未就位;

    (2)若该计算过程正常结束,或中途抛出异常,我们就说该Future已就位。

    Future的就位分为两种情况:

    (1)当Future带着某个值就位时,我们就说该Future携带计算结果成功就位。

    (2)当Future因对应计算过程抛出异常而就绪,我们就说这个Future因该异常而失败。

    Future的一个重要属性在于它只能被赋值一次。一旦给定了某个值或某个异常,future对象就变成了不可变对象——无法再被改写。

    二、创建Future

    创建future对象最简单的方法是调用future方法,该future方法启用异步(asynchronous)计算并返回保存有计算结果的futrue,一旦该future对象计算完成,其结果就变的可用。

    下面,我们举一个例子来说明。假设我们使用某些流行的社交网络的假定API获取某个用户的朋友列表,我们将打开一个新对话(session),然后发送一个请求来获取某个特定用户的好友列表。

    import scala.concurrent._
    import ExecutionContext.Implicits.global

    val session = socialNetwork.createSessionFor("user", credentials)
    val f: Future[List[Friend]] = Future {
    session.getFriends()
    }

    在上述例子中,然后我们初始化一个session变量来用作向服务器发送请求,用一个假想的 createSessionFor 方法来返回一个List[Friend]。为了获得朋友列表,我们必须通过网络发送一个请求,这个请求可能耗时很长。这能从调用getFriends方法得到解释。为了更好的利用CPU,响应到达前不应该阻塞(block)程序的其他部分执行,于是在计算中使用异步。future方法就是这样做的,它并行地执行指定的计算块,在这个例子中是向服务器发送请求和等待响应。一旦服务器响应,future f 中的好友列表将变得可用。

    三、回调函数(Callbacks)

    我们都知道Java中的Future并不是全异步的,当你需要Future里的值的时候,你只能用get去获取它,亦或者不断访问Future的状态,若完成再去取值,但其意义上便不是真正的异步了,它在获取值的时候是一个阻塞的操作,当然也就无法执行其他的操作,直到结果返回。

     但是在Scala中虽然也可以这么做,但是不推荐,因为Scala的Future提供了回调函数来获取它的结果。看如下例子:

    val fut = Future {
    Thread.sleep(1000)
    1 + 1
    }
    fut onComplete {
    case Success(r) => println(s"the result is ${r}")
    case _ => println("some Exception")
    }
    println("I am working")
    Thread.sleep(2000)

    执行结果如下:

    I am working
    the result is 2

    从结果中可以看出,我们在利用Callback方式来获取Future结果的时候并不会阻塞,而只是当Future完成后会自动调用onComplete,我们只需要根据它的结果再做处理即可,而其他互不依赖的操作可以继续执行不会阻塞。

    四、Future组合

    前面我们讲的较多的都是单个Future的情况,但是在真正实际应用时往往会遇到多个Future的情况,那么在Scala中是如何处理这种情况的呢?

    我们首先来看下面这个例子,假设我们有一个用于进行货币交易服务的API,我们想要在有盈利的时候购进一些美元。让我们先来看看怎样用回调来解决这个问题。具体代码如下:

    val rateQuote = Future {
    connection.getCurrentValue(USD)
    }

    rateQuote onSuccess { case quote =>
    val purchase = Future {
    if (isProfitable(quote)) connection.buy(amount, quote)
    else throw new Exception("not profitable")
    }

    purchase onSuccess {
    case _ => println("Purchased " + amount + " USD")
    }
    }

    从上面的代码中,我们可以看出,为了实现功能,我们将不得不在onSuccess的回调中重复这个模式,从而可能使代码过度嵌套,过于冗长,并且难以理解。另一方面,purchase只是定义在局部范围内–它只能被来自onSuccess内部的回调响应。这也就是说,这个应用的其他部分看不到purchase,而且不能为它注册其他的onSuccess回调,比如说卖掉些别的货币。

    为解决上述的两个问题,futures提供了组合器(combinators)来使之具有更多易用的组合形式。映射(map)是最基本的组合器之一。下面我们看看重构后的代码如下:

    val rateQuote = Future {
    connection.getCurrentValue(USD)
    }

    val purchase = rateQuote map { quote =>
    if (isProfitable(quote)) connection.buy(amount, quote)
    else throw new Exception("not profitable")
    }

    purchase onSuccess {
    case _ => println("Purchased " + amount + " USD")
    }

    我们可以看出,通过对rateQuote的映射我们减少了一次onSuccess的回调,更重要的是避免了嵌套。这时如果我们决定出售一些货币就可以再次使用purchase方法上的映射了。除了map组合器,Ftuture还提供了Future还拥有flatMap,filter和foreach等组合器。

    
    
    
  • 相关阅读:
    用WinForm写的员工考勤项目!!!!!!
    洛谷P1892《[BOI2003]团伙》
    洛谷P1821《[USACO07FEB]银牛派对Silver Cow Party》
    洛谷P1149《火柴棒等式》
    2017 国庆清北刷题冲刺班《角谷猜想》
    洛谷P2330《[SCOI2005]繁忙的都市》
    洛谷P1955《[NOI2015]程序自动分析》
    洛谷P1536《村村通》
    Windows 10 体验记
    洛谷P1102《A-B数对》
  • 原文地址:https://www.cnblogs.com/junjiang3/p/9501182.html
Copyright © 2011-2022 走看看