What are advantages of a Twitter Future over a Sca

2019-03-09 09:05发布

问题:

I know a lot of reasons for Scala Future to be better. Are there any reasons to use Twitter Future instead? Except the fact Finagle uses it.

回答1:

Disclaimer: I worked at Twitter on the Future implementation. A little bit of context, we started our own implementation before Scala had a "good" implementation of Future.

Here're the features of Twitter's Future:

  • Some method names are different and Twitter's Future has some new helper methods in the companion.

e.g. Just one example: Future.join(f1, f2) can work on heterogeneous Future types.

Future.join(
  Future.value(new Object), Future.value(1)
).map {
  case (o: Object, i: Int) => println(o, i)
}

o and i keep their types, they're not casted into the least common supertype Any.

  • A chain of onSuccess is guaranteed to be executed in order: e.g.:

    f.onSuccess { 
      println(1) // #1
    } onSuccess { 
      println(2) // #2
    }
    

#1 is guaranteed to be executed before #2

  • The Threading model is a little bit different. There's no notion of ExecutionContext, the Thread that set the value in a Promise (Mutable implementation of a Future) is the one executing all the computations in the future graph. e.g.:

    val f1 = new Promise[Int]
    f1.map(_ * 2).map(_ + 1)
    f1.setValue(2) // <- this thread also executes *2 and +1
    
  • There's a notion of interruption/cancellation. With Scala's Futures, the information only flows in one direction, with Twitter's Future, you can notify a producer of some information (not necessarily a cancellation). In practice, it's used in Finagle to propagate the cancellation of a RPC. Because Finagle also propagates the cancellation across the network and because Twitter has a huge fan out of requests, this actually saves lots of work.

    class MyMessage extends Exception
    
    val p = new Promise[Int]
    p.setInterruptHandler {
      case ex: MyMessage => println("Receive MyMessage")
    }
    
    val f = p.map(_ + 1).map(_ * 2)
    f.raise(new MyMessage) // print "Receive MyMessage"
    
  • Until recently, Twitter's Future were the only one to implement efficient tail recursion (i.e. you can have a recursive function that call itself without blowing up you call stack). It has been implemented in Scala 2.11+ (I believe).



回答2:

As far as I can tell the main difference that could go in favor of using Twitter's Future is that it can be cancelled, unlike scala's Future.

Also, there used to be some support for tracing the call chains (as you probably know plain stack traces are close to being useless when using Futures). In other words, you could take a Future and tell what chain of map/flatMap produced it. But the idea has been abandoned if I understand correctly.