├── project ├── build.properties └── plugins.sbt ├── benches ├── build.sbt └── src │ └── main │ └── scala │ └── scala │ ├── concurrent │ └── InternalCallbackExecutor.scala │ └── future │ ├── BenchRunner.scala │ └── Benchmarks.scala ├── README.md ├── .gitignore └── src ├── main └── scala │ └── scala │ └── future │ ├── BlockContext.scala │ ├── BatchingExecutor.scala │ ├── Promise.scala │ ├── impl │ └── Promise.scala │ └── Future.scala └── test └── scala └── concurrent └── impl └── DefaultPromiseTest.scala /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.0.4 2 | -------------------------------------------------------------------------------- /benches/build.sbt: -------------------------------------------------------------------------------- 1 | scalaVersion := "2.12.4" 2 | 3 | enablePlugins(JmhPlugin) 4 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | 2 | addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.3.3") 3 | -------------------------------------------------------------------------------- /benches/src/main/scala/scala/concurrent/InternalCallbackExecutor.scala: -------------------------------------------------------------------------------- 1 | package scala.concurrent 2 | 3 | object InternalCallbackExecutor { 4 | def apply(): ExecutionContext = Future.InternalCallbackExecutor 5 | } 6 | 7 | trait BatchingEC extends BatchingExecutor -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Improving Scala Futures 2 | 3 | This repository is a working repository to improve and optimize Scala Futures. 4 | 5 | To run the JMH benches: 6 | 7 | ``` 8 | sbt 9 | project benches 10 | jmh:runMain scala.future.BenchRunner JMH_ARGUMENTS_GO_HERE .*NAME_OF_BENCH.* 11 | ``` 12 | 13 | Examples: 14 | 15 | To run the JMH benchmark for completing Promises: 16 | 17 | ``` 18 | jmh:runMain scala.future.BenchRunner -p pool=fie -p threads=1 -p recursion=8192 -i 20 -wi 15 -f1 -t1 CompleteBenchmark* 19 | ``` 20 | 21 | To run the JMH benchmark for adding callbacks to Futures: 22 | 23 | ``` 24 | jmh:runMain scala.future.BenchRunner -p pool=fie -p threads=1 -p recursion=8192 -i 20 -wi 15 -f1 -t1 CallbackBenchmark* 25 | ``` 26 | 27 | Please open Issues or submit Pull Requests to propose more benchmarks so we can attempt to ensure that there are no regressions and so that we can quantify optimization improvements across different hardware architectures and OS setups. 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *# 2 | *.iml 3 | *.ipr 4 | *.iws 5 | *.pyc 6 | *.tm.epoch 7 | *.vim 8 | */project/boot 9 | */project/build/target 10 | */project/project.target.config-classes 11 | *~ 12 | .#* 13 | .*.swp 14 | .DS_Store 15 | .cache 16 | .cache 17 | .classpath 18 | .codefellow 19 | .ensime* 20 | .eprj 21 | .history 22 | .idea 23 | .manager 24 | .multi-jvm 25 | .project 26 | .scala_dependencies 27 | .scalastyle 28 | .settings 29 | .tags 30 | .tags_sorted_by_file 31 | .target 32 | .worksheet 33 | Makefile 34 | TAGS 35 | _akka_cluster/ 36 | _dump 37 | _mb 38 | activemq-data 39 | akka-contrib/rst_preprocessed/ 40 | akka-docs/_build/ 41 | akka-docs/exts/ 42 | akka-docs/rst_preprocessed/ 43 | akka-docs-dev/_build/ 44 | akka-docs-dev/exts/ 45 | akka-docs-dev/rst_preprocessed/ 46 | akka-osgi/src/main/resources/*.conf 47 | akka.sublime-project 48 | akka.sublime-workspace 49 | akka.tmproj 50 | beanstalk/ 51 | bin/ 52 | data 53 | deploy/*.jar 54 | etags 55 | lib_managed 56 | logs 57 | manifest.mf 58 | mongoDB/ 59 | multiverse.log 60 | out 61 | project/akka-build.properties 62 | project/boot/* 63 | project/plugins/project 64 | redis/ 65 | reports 66 | run-codefellow 67 | schoir.props 68 | semantic.cache 69 | src_managed 70 | storage 71 | tags 72 | target 73 | target-sbt 74 | tm*.lck 75 | tm*.log 76 | tm.out 77 | worker*.log 78 | *-shim.sbt 79 | test-output 80 | 81 | -------------------------------------------------------------------------------- /benches/src/main/scala/scala/future/BenchRunner.scala: -------------------------------------------------------------------------------- 1 | /** 2 | * Adapted from: https://github.com/akka/akka/blob/master/akka-bench-jmh/src/main/scala/akka/BenchRunner.scala 3 | **/ 4 | 5 | package scala.future 6 | 7 | import org.openjdk.jmh.results.RunResult 8 | import org.openjdk.jmh.runner.Runner 9 | import org.openjdk.jmh.runner.options.CommandLineOptions 10 | 11 | object BenchRunner { 12 | def main(args: Array[String]): Unit = { 13 | import scala.collection.JavaConversions._ 14 | import scala.collection.immutable 15 | 16 | val args2 = args.toList.flatMap { 17 | case "quick" => "-i 1 -wi 1 -f1 -t1".split(' ').toList 18 | case "full" => "-i 10 -wi 4 -f3 -t1".split(' ').toList 19 | case "long" => "-i 1000 -wi 4 -f3 -t1".split(' ').toList 20 | case "jitwatch" => "-jvmArgs=-XX:+UnlockDiagnosticVMOptions -XX:+TraceClassLoading -XX:+LogCompilation" :: Nil 21 | case other => other :: Nil 22 | } 23 | 24 | val opts = new CommandLineOptions(args2: _*) 25 | val results = new Runner(opts).run() 26 | 27 | val report = results.map { result: RunResult ⇒ 28 | val bench = result.getParams.getBenchmark 29 | val params = result.getParams.getParamsKeys.map(key => s"$key=${result.getParams.getParam(key)}").mkString("_") 30 | val score = result.getAggregatedResult.getPrimaryResult.getScore.round 31 | val unit = result.getAggregatedResult.getPrimaryResult.getScoreUnit 32 | s"\t${bench}_${params}\t$score\t$unit" 33 | } 34 | 35 | report.to[immutable.SortedSet].foreach(println) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/scala/scala/future/BlockContext.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scala.future 10 | 11 | import scala.concurrent.{ CanAwait } 12 | 13 | /** 14 | * A context to be notified by `scala.concurrent.blocking` when 15 | * a thread is about to block. In effect this trait provides 16 | * the implementation for `scala.concurrent.Await`. 17 | * `scala.concurrent.Await.result()` and `scala.concurrent.Await.ready()` 18 | * locates an instance of `BlockContext` by first looking for one 19 | * provided through `BlockContext.withBlockContext()` and failing that, 20 | * checking whether `Thread.currentThread` is an instance of `BlockContext`. 21 | * So a thread pool can have its `java.lang.Thread` instances implement 22 | * `BlockContext`. There's a default `BlockContext` used if the thread 23 | * doesn't implement `BlockContext`. 24 | * 25 | * Typically, you'll want to chain to the previous `BlockContext`, 26 | * like this: 27 | * {{{ 28 | * val oldContext = BlockContext.current 29 | * val myContext = new BlockContext { 30 | * override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = { 31 | * // you'd have code here doing whatever you need to do 32 | * // when the thread is about to block. 33 | * // Then you'd chain to the previous context: 34 | * oldContext.blockOn(thunk) 35 | * } 36 | * } 37 | * BlockContext.withBlockContext(myContext) { 38 | * // then this block runs with myContext as the handler 39 | * // for scala.concurrent.blocking 40 | * } 41 | * }}} 42 | */ 43 | trait BlockContext { 44 | 45 | /** Used internally by the framework; 46 | * Designates (and eventually executes) a thunk which potentially blocks the calling `java.lang.Thread`. 47 | * 48 | * Clients must use `scala.concurrent.blocking` or `scala.concurrent.Await` instead. 49 | * 50 | * In implementations of this method it is RECOMMENDED to first check if `permission` is `null` and 51 | * if it is, throw an `IllegalArgumentException`. 52 | * 53 | * @throws IllegalArgumentException if the `permission` is `null` 54 | */ 55 | def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T 56 | } 57 | 58 | object BlockContext { 59 | private final object DefaultBlockContext extends BlockContext { 60 | override def blockOn[T](thunk: =>T)(implicit permission: CanAwait): T = thunk 61 | } 62 | 63 | /** 64 | * The default block context will execute the supplied thunk immediately. 65 | * @return the `BlockContext` that will be used if no other is found. 66 | **/ 67 | final def defaultBlockContext: BlockContext = DefaultBlockContext 68 | 69 | private[this] final val contextLocal = new ThreadLocal[BlockContext]() 70 | 71 | private[this] final def prefer(candidate: BlockContext): BlockContext = 72 | if (candidate ne null) candidate 73 | else { 74 | val t = Thread.currentThread 75 | if (t.isInstanceOf[BlockContext]) t.asInstanceOf[BlockContext] 76 | else DefaultBlockContext 77 | } 78 | 79 | /** 80 | * @return the `BlockContext` that would be used for the current `java.lang.Thread` at this point 81 | **/ 82 | final def current: BlockContext = prefer(contextLocal.get) 83 | 84 | /** 85 | * Installs a current `BlockContext` around executing `body`. 86 | **/ 87 | final def withBlockContext[T](blockContext: BlockContext)(body: => T): T = { 88 | val old = contextLocal.get // can be null 89 | try { 90 | contextLocal.set(blockContext) 91 | body 92 | } finally { 93 | contextLocal.set(old) 94 | } 95 | } 96 | 97 | /** 98 | * Installs the BlockContext `blockContext` around the invocation to `f` and passes in the previously installed BlockContext to `f`. 99 | * @return the value produced by applying `f` 100 | **/ 101 | final def usingBlockContext[I, T](blockContext: BlockContext)(f: BlockContext => T): T = { 102 | val old = contextLocal.get // can be null 103 | contextLocal.set(blockContext) 104 | try f(prefer(old)) finally contextLocal.set(old) 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/scala/scala/future/BatchingExecutor.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scala.future 10 | 11 | import scala.concurrent.CanAwait 12 | import java.util.ArrayDeque 13 | import java.util.concurrent.Executor 14 | import scala.annotation.tailrec 15 | 16 | /** 17 | * Mixin trait for an Executor 18 | * which groups multiple nested `Runnable.run()` calls 19 | * into a single Runnable passed to the original 20 | * Executor. This can be a useful optimization 21 | * because it bypasses the original context's task 22 | * queue and keeps related (nested) code on a single 23 | * thread which may improve CPU affinity. However, 24 | * if tasks passed to the Executor are blocking 25 | * or expensive, this optimization can prevent work-stealing 26 | * and make performance worse. Also, some ExecutionContext 27 | * may be fast enough natively that this optimization just 28 | * adds overhead. 29 | * The default ExecutionContext.global is already batching 30 | * or fast enough not to benefit from it; while 31 | * `fromExecutor` and `fromExecutorService` do NOT add 32 | * this optimization since they don't know whether the underlying 33 | * executor will benefit from it. 34 | * A batching executor can create deadlocks if code does 35 | * not use `scala.concurrent.blocking` when it should, 36 | * because tasks created within other tasks will block 37 | * on the outer task completing. 38 | * This executor may run tasks in any order, including LIFO order. 39 | * There are no ordering guarantees. 40 | * 41 | * WARNING: The underlying Executor's execute-method must not execute the submitted Runnable 42 | * in the calling thread synchronously. It must enqueue/handoff the Runnable. 43 | */ 44 | trait BatchingExecutor extends Executor { 45 | private final val _tasksLocal = new ThreadLocal[Batch]() 46 | 47 | private[this] final class Batch(size: Int) extends ArrayDeque[Runnable](size) with Runnable with BlockContext with (BlockContext => Unit) { 48 | private[this] final var parentBlockContext: BlockContext = _ 49 | 50 | def this(r: Runnable) = { 51 | this(4) 52 | addLast(r) 53 | } 54 | 55 | final def executor: BatchingExecutor = BatchingExecutor.this 56 | 57 | // this method runs in the delegate ExecutionContext's thread 58 | override final def run(): Unit = BlockContext.usingBlockContext(this)(this) 59 | 60 | override final def apply(prevBlockContext: BlockContext): Unit = { 61 | //This invariant needs to hold: require(_tasksLocal.get eq null) 62 | parentBlockContext = prevBlockContext 63 | try { 64 | _tasksLocal.set(this) 65 | runAll() 66 | _tasksLocal.remove() // Will be cleared in the throwing-case by runAll() 67 | } finally { 68 | parentBlockContext = null 69 | } 70 | } 71 | 72 | @tailrec private[this] final def runAll(): Unit = { 73 | val next = pollLast() 74 | if (next ne null) { 75 | try next.run() catch { 76 | case t: Throwable => 77 | parentBlockContext = null // Need to reset this before re-submitting it 78 | _tasksLocal.remove() // If unbatchedExecute runs synchronously 79 | unbatchedExecute(this) //TODO what if this submission fails? 80 | throw t 81 | } 82 | runAll() 83 | } 84 | } 85 | 86 | override def blockOn[T](thunk: => T)(implicit permission: CanAwait): T = { 87 | val pbc = parentBlockContext 88 | if(!isEmpty) { // if we know there will be blocking, we don't want to keep tasks queued up because it could deadlock. 89 | val b = new Batch(math.max(4, this.size)) 90 | b.addAll(this) 91 | this.clear() 92 | unbatchedExecute(b) 93 | } 94 | 95 | if (pbc ne null) pbc.blockOn(thunk) // now delegate the blocking to the previous BC 96 | else { 97 | try thunk finally throw new IllegalStateException("BUG in BatchingExecutor.Batch: parentBlockContext is null") 98 | } 99 | } 100 | } 101 | 102 | protected def unbatchedExecute(r: Runnable): Unit 103 | 104 | override def execute(runnable: Runnable): Unit = 105 | if(batchable(runnable)) { 106 | val b = _tasksLocal.get// BlockContext.current 107 | if (b ne null) b.addLast(runnable) 108 | else unbatchedExecute(new Batch(runnable)) 109 | } else unbatchedExecute(runnable) 110 | 111 | /** Override this to define which runnables will be batched. */ 112 | def batchable(runnable: Runnable): Boolean = runnable.isInstanceOf[OnCompleteRunnable] 113 | } -------------------------------------------------------------------------------- /src/main/scala/scala/future/Promise.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scala.future 10 | 11 | import scala.util.{ Try, Success, Failure } 12 | 13 | /** Promise is an object which can be completed with a value or failed 14 | * with an exception. 15 | * 16 | * @define promiseCompletion 17 | * If the promise has already been fulfilled, failed or has timed out, 18 | * calling this method will throw an IllegalStateException. 19 | * 20 | * @define allowedThrowables 21 | * If the throwable used to fail this promise is an error, a control exception 22 | * or an interrupted exception, it will be wrapped as a cause within an 23 | * `ExecutionException` which will fail the promise. 24 | * 25 | * @define nonDeterministic 26 | * Note: Using this method may result in non-deterministic concurrent programs. 27 | */ 28 | trait Promise[T] { 29 | /** Future containing the value of this promise. 30 | */ 31 | def future: Future[T] 32 | 33 | /** Returns whether the promise has already been completed with 34 | * a value or an exception. 35 | * 36 | * $nonDeterministic 37 | * 38 | * @return `true` if the promise is already completed, `false` otherwise 39 | */ 40 | def isCompleted: Boolean 41 | 42 | /** Completes the promise with either an exception or a value. 43 | * 44 | * @param result Either the value or the exception to complete the promise with. 45 | * 46 | * $promiseCompletion 47 | */ 48 | def complete(result: Try[T]): this.type = 49 | if (tryComplete(result)) this else throw new IllegalStateException("Promise already completed.") 50 | 51 | /** Tries to complete the promise with either a value or the exception. 52 | * 53 | * $nonDeterministic 54 | * 55 | * @return If the promise has already been completed returns `false`, or `true` otherwise. 56 | */ 57 | def tryComplete(result: Try[T]): Boolean 58 | 59 | /** Completes this promise with the specified future, once that future is completed. 60 | * 61 | * @return This promise 62 | */ 63 | def completeWith(other: Future[T]): this.type = { 64 | if (other ne this.future) { // this tryCompleteWith this doesn't make much sense 65 | other.onComplete(this tryComplete _)(Future.InternalCallbackExecutor) 66 | } 67 | this 68 | } 69 | 70 | /** Attempts to complete this promise with the specified future, once that future is completed. 71 | * 72 | * @return This promise 73 | */ 74 | @deprecated("Since this method is semantically equivalent to `completeWith`, use that instead.", "2.13") 75 | final def tryCompleteWith(other: Future[T]): this.type = completeWith(other) 76 | 77 | /** Completes the promise with a value. 78 | * 79 | * @param value The value to complete the promise with. 80 | * 81 | * $promiseCompletion 82 | */ 83 | def success(@deprecatedName('v) value: T): this.type = complete(Success(value)) 84 | 85 | /** Tries to complete the promise with a value. 86 | * 87 | * $nonDeterministic 88 | * 89 | * @return If the promise has already been completed returns `false`, or `true` otherwise. 90 | */ 91 | def trySuccess(value: T): Boolean = tryComplete(Success(value)) 92 | 93 | /** Completes the promise with an exception. 94 | * 95 | * @param cause The throwable to complete the promise with. 96 | * 97 | * $allowedThrowables 98 | * 99 | * $promiseCompletion 100 | */ 101 | def failure(@deprecatedName('t) cause: Throwable): this.type = complete(Failure(cause)) 102 | 103 | /** Tries to complete the promise with an exception. 104 | * 105 | * $nonDeterministic 106 | * 107 | * @return If the promise has already been completed returns `false`, or `true` otherwise. 108 | */ 109 | def tryFailure(@deprecatedName('t) cause: Throwable): Boolean = tryComplete(Failure(cause)) 110 | } 111 | 112 | object Promise { 113 | /** Creates a promise object which can be completed with a value. 114 | * 115 | * @tparam T the type of the value in the promise 116 | * @return the newly created `Promise` instance 117 | */ 118 | def apply[T](): Promise[T] = new impl.Promise.DefaultPromise[T]() 119 | 120 | /** Creates an already completed Promise with the specified exception. 121 | * 122 | * @tparam T the type of the value in the promise 123 | * @return the newly created `Promise` instance 124 | */ 125 | def failed[T](exception: Throwable): Promise[T] = new impl.Promise.DefaultPromise[T](Failure(exception)) 126 | 127 | /** Creates an already completed Promise with the specified result. 128 | * 129 | * @tparam T the type of the value in the promise 130 | * @return the newly created `Promise` instance 131 | */ 132 | def successful[T](result: T): Promise[T] = new impl.Promise.DefaultPromise[T](Success(result)) 133 | 134 | /** Creates an already completed Promise with the specified result or exception. 135 | * 136 | * @tparam T the type of the value in the promise 137 | * @return the newly created `Promise` instance 138 | */ 139 | def fromTry[T](result: Try[T]): Promise[T] = new impl.Promise.DefaultPromise[T](result) 140 | } 141 | -------------------------------------------------------------------------------- /src/test/scala/concurrent/impl/DefaultPromiseTest.scala: -------------------------------------------------------------------------------- 1 | package scala.future.impl 2 | 3 | import java.util.concurrent.{ ConcurrentLinkedQueue, CountDownLatch, Executor, Executors, ExecutionException, RejectedExecutionException } 4 | import org.junit.Assert._ 5 | import org.junit.{ After, Before, Test } 6 | import org.junit.runner.RunWith 7 | import org.junit.runners.JUnit4 8 | import scala.annotation.tailrec 9 | import scala.concurrent.{ ExecutionContext, Await } 10 | import scala.concurrent.duration._ 11 | import scala.future.impl.Promise.DefaultPromise 12 | import scala.util.{ Failure, Success, Try } 13 | import scala.util.control.NonFatal 14 | 15 | /** Tests for the private class DefaultPromise */ 16 | //@RunWith(classOf[JUnit4]) 17 | class DefaultPromiseTest { 18 | 19 | // Many tests in this class use a helper class, Tester, to track the state of 20 | // promises and to ensure they behave correctly, particularly the complex behaviour 21 | // of linking. 22 | 23 | type Result = Int 24 | type PromiseId = Int 25 | type HandlerId = Int 26 | type ChainId = Int 27 | 28 | /** The state of a set of set of linked promises. */ 29 | final case class Chain( 30 | promises: Set[PromiseId], 31 | state: Either[Set[HandlerId],Try[Result]] 32 | ) 33 | 34 | /** A helper class that provides methods for creating, linking, completing and 35 | * adding handlers to promises. With each operation it verifies that handlers 36 | * are called, any expected exceptions are thrown, and that all promises have 37 | * the expected value. 38 | * 39 | * The links between promises are not tracked precisely. Instead, linked promises 40 | * are placed in the same Chain object. Each link in the same chain will share 41 | * the same value. 42 | */ 43 | class Tester { 44 | var promises = Map.empty[PromiseId, DefaultPromise[Result]] 45 | var chains = Map.empty[ChainId, Chain] 46 | 47 | private var counter = 0 48 | private def freshId(): Int = { 49 | val id = counter 50 | counter += 1 51 | id 52 | } 53 | 54 | /** Handlers report their activity on this queue */ 55 | private val handlerQueue = new ConcurrentLinkedQueue[(Try[Result], HandlerId)]() 56 | 57 | /** Get the chain for a given promise */ 58 | private def promiseChain(p: PromiseId): Option[(ChainId, Chain)] = { 59 | val found: Iterable[(ChainId, Chain)] = for ((cid, c) <- chains; p0 <- c.promises; if (p0 == p)) yield ((cid, c)) 60 | found.toList match { 61 | case Nil => None 62 | case x::Nil => Some(x) 63 | case _ => throw new IllegalStateException(s"Promise $p found in more than one chain") 64 | } 65 | } 66 | 67 | /** Passed to `checkEffect` to indicate the expected effect of an operation */ 68 | sealed trait Effect 69 | case object NoEffect extends Effect 70 | case class HandlersFired(result: Try[Result], handlers: Set[HandlerId]) extends Effect 71 | case object MaybeIllegalThrown extends Effect 72 | case object IllegalThrown extends Effect 73 | 74 | /** Runs an operation while verifying that the operation has the expected effect */ 75 | private def checkEffect(expected: Effect)(f: => Any): Unit = { 76 | assert(handlerQueue.isEmpty()) // Should have been cleared by last usage 77 | val result = Try(f) 78 | 79 | var fireCounts = Map.empty[(Try[Result], HandlerId), Int] 80 | while (!handlerQueue.isEmpty()) { 81 | val key = handlerQueue.poll() 82 | val newCount = fireCounts.getOrElse(key, 0) + 1 83 | fireCounts = fireCounts.updated(key, newCount) 84 | } 85 | 86 | def assertIllegalResult() = result match { 87 | case Failure(e: IllegalStateException) => () 88 | case _ => fail(s"Expected IllegalStateException: $result") 89 | } 90 | 91 | expected match { 92 | case NoEffect => 93 | assertTrue(s"Shouldn't throw exception: $result", result.isSuccess) 94 | assertEquals(Map.empty[(Try[Result], HandlerId), Int], fireCounts) 95 | case HandlersFired(firingResult, handlers) => 96 | assert(result.isSuccess) 97 | val expectedCounts = handlers.foldLeft(Map.empty[(Try[Result], HandlerId), Int]) { 98 | case (map, hid) => map.updated((firingResult, hid), 1) 99 | } 100 | assertEquals(expectedCounts, fireCounts) 101 | case MaybeIllegalThrown => 102 | if (result.isFailure) assertIllegalResult 103 | assertEquals(Map.empty, fireCounts) 104 | case IllegalThrown => 105 | assertIllegalResult 106 | assertEquals(Map.empty, fireCounts) 107 | } 108 | } 109 | 110 | /** Check each promise has the expected value. */ 111 | private def assertPromiseValues(): Unit = { 112 | for ((cid, chain) <- chains; p <- chain.promises) { 113 | chain.state match { 114 | case Right(result) => assertEquals(Some(result), promises(p).value) 115 | case Left(_) => () 116 | } 117 | } 118 | } 119 | 120 | /** Create a promise, returning a handle. */ 121 | def newPromise(): PromiseId = { 122 | val pid = freshId() 123 | val cid = freshId() 124 | promises = promises.updated(pid, new DefaultPromise[Result]()) 125 | chains = chains.updated(cid, Chain(Set(pid), Left(Set.empty))) 126 | assertPromiseValues() 127 | pid 128 | } 129 | 130 | /** Complete a promise */ 131 | def complete(p: PromiseId): Unit = { 132 | val r = Success(freshId()) 133 | val (cid, chain) = promiseChain(p).get 134 | val (completionEffect, newState) = chain.state match { 135 | case Left(handlers) => (HandlersFired(r, handlers), Right(r)) 136 | case Right(completion) => (IllegalThrown, chain.state) 137 | } 138 | checkEffect(completionEffect) { promises(p).complete(r) } 139 | chains = chains.updated(cid, chain.copy(state = newState)) 140 | assertPromiseValues() 141 | } 142 | 143 | /** Attempt to link two promises together */ 144 | def link(a: PromiseId, b: PromiseId): (ChainId, ChainId) = { 145 | val promiseA = promises(a) 146 | val promiseB = promises(b) 147 | val (cidA, chainA) = promiseChain(a).get 148 | val (cidB, chainB) = promiseChain(b).get 149 | 150 | // Examine the state of each promise's chain to work out 151 | // the effect of linking the promises, and to work out 152 | // if the two chains should be merged. 153 | 154 | sealed trait MergeOp 155 | case object NoMerge extends MergeOp 156 | case class Merge(state: Either[Set[HandlerId],Try[Result]]) extends MergeOp 157 | 158 | val (linkEffect, mergeOp) = (chainA.state, chainB.state) match { 159 | case (Left(handlers1), Left(handlers2)) => 160 | (NoEffect, Merge(Left(handlers1 ++ handlers2))) 161 | case (Left(handlers), Right(result)) => 162 | (HandlersFired(result, handlers), Merge(Right(result))) 163 | case (Right(result), Left(handlers)) => 164 | (HandlersFired(result, handlers), Merge(Right(result))) 165 | case (Right(_), Right(_)) if (cidA == cidB) => 166 | (MaybeIllegalThrown, NoMerge) // Won't be thrown if happen to link a promise to itself 167 | case (Right(_), Right(_)) => 168 | (IllegalThrown, NoMerge) 169 | } 170 | 171 | // Perform the linking and merge the chains, if appropriate 172 | 173 | checkEffect(linkEffect) { promiseA.linkRootOf(promiseB) } 174 | 175 | val (newCidA, newCidB) = mergeOp match { 176 | case NoMerge => (cidA, cidB) 177 | case Merge(newState) => { 178 | chains = chains - cidA 179 | chains = chains - cidB 180 | val newCid = freshId() 181 | chains = chains.updated(newCid, Chain(chainA.promises ++ chainB.promises, newState)) 182 | (newCid, newCid) 183 | } 184 | } 185 | assertPromiseValues() 186 | (newCidA, newCidB) 187 | } 188 | 189 | /** Attach an onComplete handler. When called, the handler will 190 | * place an entry into `handlerQueue` with the handler's identity. 191 | * This allows verification of handler calling semantics. 192 | */ 193 | def attachHandler(p: PromiseId): HandlerId = { 194 | val hid = freshId() 195 | val promise = promises(p) 196 | val (cid, chain) = promiseChain(p).get 197 | val (attachEffect, newState) = chain.state match { 198 | case Left(handlers) => 199 | (NoEffect, Left(handlers + hid)) 200 | case Right(result) => 201 | (HandlersFired(result, Set(hid)), Right(result)) 202 | } 203 | implicit val ec = new ExecutionContext { 204 | def execute(r: Runnable) { r.run() } 205 | def reportFailure(t: Throwable) { t.printStackTrace() } 206 | } 207 | 208 | checkEffect(attachEffect) { promise.onComplete(result => handlerQueue.add((result, hid))) } 209 | chains = chains.updated(cid, chain.copy(state = newState)) 210 | assertPromiseValues() 211 | hid 212 | } 213 | } 214 | 215 | // Some methods and objects that build a list of promise 216 | // actions to test and then execute them 217 | 218 | type PromiseKey = Int 219 | 220 | sealed trait Action 221 | case class Complete(p: PromiseKey) extends Action 222 | case class Link(a: PromiseKey, b: PromiseKey) extends Action 223 | case class AttachHandler(p: PromiseKey) extends Action 224 | 225 | /** Tests a sequence of actions on a Tester. Creates promises as needed. */ 226 | private def testActions(actions: Seq[Action]): Unit = { 227 | val t = new Tester() 228 | var pMap = Map.empty[PromiseKey, PromiseId] 229 | def byKey(key: PromiseKey): PromiseId = { 230 | if (!pMap.contains(key)) { 231 | pMap = pMap.updated(key, t.newPromise()) 232 | } 233 | pMap(key) 234 | } 235 | 236 | actions foreach { action => 237 | action match { 238 | case Complete(p) => t.complete(byKey(p)) 239 | case Link(a, b) => t.link(byKey(a), byKey(b)) 240 | case AttachHandler(p) => t.attachHandler(byKey(p)) 241 | } 242 | } 243 | } 244 | 245 | /** Tests all permutations of actions for `count` promises */ 246 | private def testPermutations(count: Int): Unit = { 247 | val ps = (0 until count).toList 248 | val pPairs = for (a <- ps; b <- ps) yield (a, b) 249 | 250 | val allActions = ps.map(Complete(_)) ++ pPairs.map { case (a, b) => Link(a, b) } ++ ps.map(AttachHandler(_)) 251 | for ((permutation, i) <- allActions.permutations.zipWithIndex) { 252 | testActions(permutation) 253 | } 254 | } 255 | 256 | /** Test all permutations of actions with a single promise */ 257 | @Test 258 | def testPermutations1(): Unit = { 259 | testPermutations(1) 260 | } 261 | 262 | /** Test all permutations of actions with two promises - about 40 thousand */ 263 | @Test 264 | def testPermutations2(): Unit = { 265 | testPermutations(2) 266 | } 267 | 268 | /** Link promises in different orders, using the same link structure as is 269 | * used in Future.flatMap */ 270 | @Test 271 | def simulateFlatMapLinking(): Unit = { 272 | val random = new scala.util.Random(1) 273 | for (_ <- 0 until 10) { 274 | val t = new Tester() 275 | val flatMapCount = 100 276 | 277 | sealed trait FlatMapEvent 278 | case class Link(a: PromiseId, b: PromiseId) extends FlatMapEvent 279 | case class Complete(p: PromiseId) extends FlatMapEvent 280 | 281 | @tailrec 282 | def flatMapEvents(count: Int, p1: PromiseId, acc: List[FlatMapEvent]): List[FlatMapEvent] = { 283 | if (count == 0) { 284 | Complete(p1)::acc 285 | } else { 286 | val p2 = t.newPromise() 287 | flatMapEvents(count - 1, p2, Link(p2, p1)::acc) 288 | } 289 | } 290 | 291 | val events = flatMapEvents(flatMapCount, t.newPromise(), Nil) 292 | assertEquals(flatMapCount + 1, t.chains.size) // All promises are unlinked 293 | val shuffled = random.shuffle(events) 294 | shuffled foreach { 295 | case Link(a, b) => t.link(a, b) 296 | case Complete(p) => t.complete(p) 297 | } 298 | // All promises should be linked together, no matter the order of their linking 299 | assertEquals(1, t.chains.size) 300 | } 301 | } 302 | 303 | /** Link promises together on more than one thread, using the same link 304 | * structure as is used in Future.flatMap */ 305 | @Test 306 | def testFlatMapLinking(): Unit = { 307 | for (_ <- 0 until 100) { 308 | val flatMapCount = 100 309 | val startLatch = new CountDownLatch(1) 310 | val doneLatch = new CountDownLatch(flatMapCount + 1) 311 | def execute(f: => Unit) { 312 | val ec = ExecutionContext.global 313 | ec.execute(new Runnable { 314 | def run() { 315 | try { 316 | startLatch.await() 317 | f 318 | doneLatch.countDown() 319 | } catch { 320 | case NonFatal(e) => ec.reportFailure(e) 321 | } 322 | } 323 | }) 324 | } 325 | @tailrec 326 | def flatMapTimes(count: Int, p1: DefaultPromise[Int]) { 327 | if (count == 0) { 328 | execute { p1.success(1) } 329 | } else { 330 | val p2 = new DefaultPromise[Int]() 331 | execute { p2.linkRootOf(p1) } 332 | flatMapTimes(count - 1, p2) 333 | } 334 | } 335 | 336 | val p = new DefaultPromise[Int]() 337 | flatMapTimes(flatMapCount, p) 338 | startLatch.countDown() 339 | doneLatch.await() 340 | assertEquals(Some(Success(1)), p.value) 341 | } 342 | } 343 | 344 | @Test 345 | def interruptHandling(): Unit = { 346 | implicit val e = ExecutionContext.fromExecutorService(Executors.newFixedThreadPool(1)) 347 | val p = new DefaultPromise[String]() 348 | val f = p.future.map(_ => Thread.sleep(2000)) 349 | p.success("foo") 350 | Thread.sleep(20) 351 | e.shutdownNow() 352 | 353 | val Failure(ee: ExecutionException) = Await.ready(f, 2.seconds).value.get 354 | assertTrue(ee.getCause.isInstanceOf[InterruptedException]) 355 | } 356 | 357 | @Test 358 | def rejectedExecutionException(): Unit = { 359 | implicit val e = ExecutionContext.fromExecutor((r: Runnable) => throw new RejectedExecutionException("foo")) 360 | val p = new DefaultPromise[String]() 361 | p.success("foo") 362 | val f = p.future.map(identity) 363 | val Failure(t: RejectedExecutionException) = Await.ready(f, 2.seconds).value.get 364 | } 365 | 366 | } 367 | -------------------------------------------------------------------------------- /src/main/scala/scala/future/impl/Promise.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scala.future.impl 10 | import scala.concurrent.{ExecutionContext, CanAwait, TimeoutException, ExecutionException } 11 | import scala.future.{ Future, OnCompleteRunnable } 12 | import scala.future.Future.InternalCallbackExecutor 13 | import scala.concurrent.duration.Duration 14 | import scala.annotation.{ tailrec, unchecked, switch } 15 | import scala.util.control.{ NonFatal, ControlThrowable } 16 | import scala.util.{ Try, Success, Failure } 17 | import scala.runtime.NonLocalReturnControl 18 | import java.util.concurrent.locks.AbstractQueuedSynchronizer 19 | import java.util.concurrent.atomic.AtomicReference 20 | import java.util.Objects.requireNonNull 21 | 22 | private[future] final object Promise { 23 | /** 24 | * Latch used to implement waiting on a DefaultPromise's result. 25 | * 26 | * Inspired by: http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/locks/AbstractQueuedSynchronizer.java 27 | * Written by Doug Lea with assistance from members of JCP JSR-166 28 | * Expert Group and released to the public domain, as explained at 29 | * http://creativecommons.org/publicdomain/zero/1.0/ 30 | */ 31 | private final class CompletionLatch[T] extends AbstractQueuedSynchronizer with (Try[T] => Unit) { 32 | //@volatie not needed since we use acquire/release 33 | /*@volatile*/ private[this] var _result: Try[T] = null 34 | final def result: Try[T] = _result 35 | override protected def tryAcquireShared(ignored: Int): Int = if (getState != 0) 1 else -1 36 | override protected def tryReleaseShared(ignore: Int): Boolean = { 37 | setState(1) 38 | true 39 | } 40 | override def apply(value: Try[T]): Unit = { 41 | _result = value // This line MUST go before releaseShared 42 | releaseShared(1) 43 | } 44 | } 45 | 46 | // requireNonNull is paramount to guard against null completions 47 | private[this] final def resolve[T](value: Try[T]): Try[T] = 48 | if (requireNonNull(value).isInstanceOf[Success[T]]) value 49 | else { 50 | val t = value.asInstanceOf[Failure[T]].exception 51 | if (t.isInstanceOf[ControlThrowable] || t.isInstanceOf[InterruptedException] || t.isInstanceOf[Error]) { 52 | if (t.isInstanceOf[NonLocalReturnControl[T @unchecked]]) 53 | Success(t.asInstanceOf[NonLocalReturnControl[T]].value) 54 | else 55 | Failure(new ExecutionException("Boxed Exception", t)) 56 | } else value 57 | } 58 | 59 | // Left non-final to enable addition of extra fields by Java/Scala converters in scala-java8-compat. 60 | class DefaultPromise[T] private[this] (initial: AnyRef) extends AtomicReference[AnyRef](initial) with scala.future.Promise[T] with scala.future.Future[T] { 61 | /** 62 | * Constructs a new, completed, Promise. 63 | */ 64 | def this(result: Try[T]) = this(resolve(result): AnyRef) 65 | 66 | /** 67 | * Constructs a new, un-completed, Promise. 68 | */ 69 | def this() = this(Callbacks.empty: AnyRef) 70 | 71 | /** 72 | * Returns the associaed `Future` with this `Promise` 73 | */ 74 | override final def future: Future[T] = this 75 | 76 | override final def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S] = 77 | dispatchOrAddCallbacks(get(), new Transformation[T, S](Xform_transform, f, executor)) 78 | 79 | override final def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S] = 80 | dispatchOrAddCallbacks(get(), new Transformation[T, S](Xform_transformWith, f, executor)) 81 | 82 | override final def onFailure[U](@deprecatedName('callback) pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = 83 | if (!get().isInstanceOf[Success[T]]) super[Future].onFailure(pf) // Short-circuit if we get a Failure 84 | 85 | override final def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit = 86 | if (!get().isInstanceOf[Failure[T]]) super[Future].onSuccess(pf) // Short-circuit if we get a Success 87 | 88 | override final def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit = { 89 | val state = get() 90 | if (!state.isInstanceOf[Failure[T]]) dispatchOrAddCallbacks(state, new Transformation[T, Unit](Xform_foreach, f, executor)) 91 | } 92 | 93 | override final def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = { 94 | val state = get() 95 | if (!state.isInstanceOf[Failure[T]]) dispatchOrAddCallbacks(state, new Transformation[T, S](Xform_flatMap, f, executor)) 96 | else this.asInstanceOf[Future[S]] 97 | } 98 | 99 | override final def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = { 100 | val state = get() 101 | if (!state.isInstanceOf[Failure[T]]) dispatchOrAddCallbacks(state, new Transformation[T, S](Xform_map, f, executor)) 102 | else this.asInstanceOf[Future[S]] 103 | } 104 | 105 | override final def filter(@deprecatedName('pred) p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = { 106 | val state = get() 107 | if (!state.isInstanceOf[Failure[T]]) dispatchOrAddCallbacks(state, new Transformation[T, T](Xform_filter, p, executor)) // Short-circuit if we get a Success 108 | else this 109 | } 110 | 111 | override final def collect[S](pf: PartialFunction[T, S])(implicit executor: ExecutionContext): Future[S] = { 112 | val state = get() 113 | if (!state.isInstanceOf[Failure[T]]) dispatchOrAddCallbacks(state, new Transformation[T, S](Xform_collect, pf, executor)) // Short-circuit if we get a Success 114 | else this.asInstanceOf[Future[S]] 115 | } 116 | 117 | override final def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = { 118 | val state = get() 119 | if (!state.isInstanceOf[Success[T]]) dispatchOrAddCallbacks(state, new Transformation[T, U](Xform_recoverWith, pf, executor)) // Short-circuit if we get a Failure 120 | else this.asInstanceOf[Future[U]] 121 | } 122 | 123 | override final def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = { 124 | val state = get() 125 | if (!state.isInstanceOf[Success[T]]) dispatchOrAddCallbacks(state, new Transformation[T, U](Xform_recover, pf, executor)) // Short-circuit if we get a Failure 126 | else this.asInstanceOf[Future[U]] 127 | } 128 | 129 | override final def mapTo[S](implicit tag: scala.reflect.ClassTag[S]): Future[S] = 130 | if (!get.isInstanceOf[Failure[T]]) super[Future].mapTo[S](tag) // Short-circuit if we get a Success 131 | else this.asInstanceOf[Future[S]] 132 | 133 | 134 | override def toString: String = toString0 135 | 136 | @tailrec private final def toString0: String = { 137 | val state = get() 138 | if (state.isInstanceOf[Try[T]]) "Future("+state+")" 139 | else if (state.isInstanceOf[DefaultPromise[T]]) compressedRoot(state.asInstanceOf[DefaultPromise[T]], this).toString0 140 | else /*if (state.isInstanceOf[Callbacks[T]]) */ "Future()" 141 | } 142 | 143 | /** Try waiting for this promise to be completed. 144 | * Returns true if it completed at the end of this waiting time. 145 | * Does not allow Duration.Undefined as a parameter, and throws IllegalArgumentException 146 | * if it is passed in. 147 | */ 148 | protected final def tryAwait(atMost: Duration): Boolean = tryAwait0(atMost) ne null 149 | 150 | private[this] final def tryAwait0(atMost: Duration): Try[T] = 151 | if (atMost ne Duration.Undefined) { 152 | val v = value0 153 | if ((v ne null) || atMost <= Duration.Zero) v 154 | else { 155 | val l = new CompletionLatch[T]() 156 | onComplete(l)(InternalCallbackExecutor) 157 | 158 | if (atMost.isFinite) 159 | l.tryAcquireSharedNanos(1, atMost.toNanos) 160 | else 161 | l.acquireSharedInterruptibly(1) 162 | 163 | l.result 164 | } 165 | } else throw new IllegalArgumentException("Cannot wait for Undefined duration of time") 166 | 167 | @throws(classOf[TimeoutException]) 168 | @throws(classOf[InterruptedException]) 169 | final def ready(atMost: Duration)(implicit permit: CanAwait): this.type = { 170 | val v = tryAwait0(atMost) 171 | if (v ne null) this 172 | else throw new TimeoutException("Future timed out after [" + atMost + "]") 173 | } 174 | 175 | @throws(classOf[Exception]) 176 | final def result(atMost: Duration)(implicit permit: CanAwait): T = { 177 | val v = tryAwait0(atMost) 178 | if (v ne null) v.get // returns the value, or throws the contained exception 179 | else throw new TimeoutException("Future timed out after [" + atMost + "]") 180 | } 181 | 182 | override final def isCompleted: Boolean = value0 ne null 183 | 184 | override final def value: Option[Try[T]] = Option(value0) 185 | 186 | @tailrec 187 | private final def value0: Try[T] = { 188 | val state = get() 189 | if (state.isInstanceOf[Try[T]]) state.asInstanceOf[Try[T]] 190 | else if (state.isInstanceOf[DefaultPromise[T]]) compressedRoot(state.asInstanceOf[DefaultPromise[T]], this).value0 191 | else /*if (state.isInstanceOf[Callbacks[T]])*/ null 192 | } 193 | 194 | override final def tryComplete(value: Try[T]): Boolean = { 195 | val state = get() 196 | if (state.isInstanceOf[Try[T]]) false 197 | else tryComplete0(state, resolve(value)) 198 | } 199 | 200 | @tailrec 201 | private final def tryComplete0(state: AnyRef, resolved: Try[T]): Boolean = 202 | if (state.isInstanceOf[Callbacks[T]]) { 203 | if (compareAndSet(state, resolved)) { 204 | if (state ne Callbacks.empty) submitWithValue(state.asInstanceOf[Callbacks[T]], resolved) 205 | true 206 | } else tryComplete0(get(), resolved) 207 | } else if (state.isInstanceOf[DefaultPromise[T]]) { 208 | val p = compressedRoot(state.asInstanceOf[DefaultPromise[T]], this) // If this returns owner/this, we are in a completed link 209 | (p ne this) && p.tryComplete0(p.get(), resolved) // Use this to get tailcall optimization and avoid re-resolution 210 | } else /* if(state.isInstanceOf[Try[T]]) */ false 211 | 212 | override final def onComplete[U](func: Try[T] => U)(implicit executor: ExecutionContext): Unit = 213 | dispatchOrAddCallbacks(get(), new Transformation[T, Unit](Xform_onComplete, func, executor)) 214 | 215 | /** Tries to add the callback, if already completed, it dispatches the callback to be executed. 216 | * Used by `onComplete()` to add callbacks to a promise and by `link()` to transfer callbacks 217 | * to the root promise when linking two promises together. 218 | */ 219 | @tailrec private final def dispatchOrAddCallbacks[C <: Callback[T]](state: AnyRef, callbacks: C): C = 220 | if (state.isInstanceOf[Try[T]]) { 221 | submitWithValue(callbacks, state.asInstanceOf[Try[T]]) 222 | callbacks 223 | } else if (state.isInstanceOf[Callbacks[T]]) { 224 | val newCallbacks = if(state ne Callbacks.empty) new Callbacks(callbacks, state.asInstanceOf[Callbacks[T]]) 225 | else new Callbacks(callbacks) 226 | if(compareAndSet(state, newCallbacks)) callbacks 227 | else dispatchOrAddCallbacks(get(), callbacks) 228 | } else /*if (state.isInstanceOf[DefaultPromise[T]])*/ { 229 | val p = compressedRoot(state.asInstanceOf[DefaultPromise[T]], this) 230 | p.dispatchOrAddCallbacks(p.get(), callbacks) 231 | } 232 | 233 | private[this] final def submitWithValue(cb: Callback[T], v: Try[T]): Unit = 234 | if (cb.isInstanceOf[Callbacks[T]]) { 235 | // FIXME: this will grow the stack—needs real-world proofing. Most of the time `first` will be a Tranformation though. 236 | val m = cb.asInstanceOf[Callbacks[T]] 237 | val mf = m.first 238 | val ml = m.last 239 | if (mf.isInstanceOf[Transformation[T,_]] && (mf ne Callbacks.noop)) mf.asInstanceOf[Transformation[T,_]].submitWithValue(v) 240 | else submitWithValue(mf, v) 241 | if (ml.isInstanceOf[Transformation[T,_]] && (ml ne Callbacks.noop)) ml.asInstanceOf[Transformation[T,_]].submitWithValue(v) 242 | else submitWithValue(ml, v) 243 | } else cb.asInstanceOf[Transformation[T,_]].submitWithValue(v) 244 | 245 | /** Get the root promise for this promise, compressing the link chain to that 246 | * promise if necessary. 247 | * 248 | * For promises that are not linked, the result of calling 249 | * `compressedRoot()` will the promise itself. However for linked promises, 250 | * this method will traverse each link until it locates the root promise at 251 | * the base of the link chain. 252 | * 253 | * As a side effect of calling this method, the link from this promise back 254 | * to the root promise will be updated ("compressed") to point directly to 255 | * the root promise. This allows intermediate promises in the link chain to 256 | * be garbage collected. Also, subsequent calls to this method should be 257 | * faster as the link chain will be shorter. 258 | */ 259 | @tailrec protected[future] final def compressedRoot(linked: DefaultPromise[T], owner: DefaultPromise[T]): DefaultPromise[T] = { 260 | 261 | @tailrec def rootOf(current: DefaultPromise[T], owner: DefaultPromise[T]): DefaultPromise[T] = { 262 | val state = current.get() 263 | if (state.isInstanceOf[DefaultPromise[T]]) rootOf(state.asInstanceOf[DefaultPromise[T]], owner) 264 | else if(state.isInstanceOf[Try[T]]) { 265 | @tailrec def unlink(owner: DefaultPromise[T], value: Try[T]): Unit = { 266 | val l = owner.get() 267 | if (l.isInstanceOf[DefaultPromise[T]]) 268 | unlink(if (owner.compareAndSet(l, value)) l.asInstanceOf[DefaultPromise[T]] else owner, value ) 269 | else if(l.isInstanceOf[Callbacks[T]]) owner.tryComplete0(owner.get(), value) 270 | else /* if (l.isInstanceOf[Try[T]]) */ () 271 | } 272 | unlink(owner, state.asInstanceOf[Try[T]]) 273 | owner 274 | } else current 275 | } 276 | 277 | val target = rootOf(linked, owner) 278 | if ((linked eq target) || (owner eq target) || compareAndSet(linked, target)) target 279 | else { 280 | val state = get() 281 | if (state.isInstanceOf[DefaultPromise[T]]) compressedRoot(state.asInstanceOf[DefaultPromise[T]], owner) 282 | else this 283 | } 284 | } 285 | 286 | /** Link this promise to the root of another promise using `link()`. Should only be 287 | * be called by transformWith. 288 | */ 289 | protected[future] final def linkRootOf(target: DefaultPromise[T]): Unit = { 290 | /** Link this promise to another promise so that both promises share the same 291 | * externally-visible state. Depending on the current state of this promise, this 292 | * may involve different things. For example, any onComplete callbacks will need 293 | * to be transferred. 294 | * 295 | * If this promise is already completed, then the same effect as linking - 296 | * sharing the same completed value - is achieved by simply sending this 297 | * promise's result to the target promise. 298 | */ 299 | @tailrec def link(owner: DefaultPromise[T], target: DefaultPromise[T]): Unit = if (owner ne target) { 300 | val state = owner.get() 301 | if (state.isInstanceOf[Try[T]]) { 302 | if (!target.tryComplete(state.asInstanceOf[Try[T]])) 303 | throw new IllegalStateException("Cannot link completed promises together") 304 | } 305 | else if (state.isInstanceOf[DefaultPromise[T]]) link(owner.compressedRoot(state.asInstanceOf[DefaultPromise[T]], this), target) 306 | else if (compareAndSet(state, target)) target.dispatchOrAddCallbacks(target.get(), state.asInstanceOf[Callbacks[T]]) 307 | else link(owner, target) 308 | } 309 | link(this, target.compressedRoot(target, target)) // FIXME correct owner to compressedRoot here? 310 | } 311 | } 312 | 313 | // Byte tags for unpacking transformation function inputs or outputs 314 | final val Xform_map = 0 315 | final val Xform_flatMap = 1 316 | final val Xform_transform = 2 317 | final val Xform_transformWith = 3 318 | final val Xform_foreach = 4 319 | final val Xform_onComplete = 5 320 | final val Xform_recover = 6 321 | final val Xform_recoverWith = 7 322 | final val Xform_filter = 8 323 | final val Xform_collect = 9 324 | 325 | /* Marker trait 326 | */ 327 | sealed trait Callback[-T] 328 | final object Callbacks { 329 | final val noop = new Transformation[Any, Any](-127, null, InternalCallbackExecutor) 330 | final val empty = new Callbacks[Nothing](noop, noop) 331 | } 332 | final class Callbacks[-T] private[Callbacks] (final val first: Callback[T], final val last: Callback[T]) extends Callback[T] { 333 | final def this(first: Callback[T]) = this(Callbacks.noop, first) 334 | final def this(first: Callback[T], last: Callbacks[T]) = this(first, if (last.first eq Callbacks.noop) last.last else last) 335 | override final def toString: String = "Callbacks" 336 | } 337 | 338 | final class Transformation[-F, T] private[this] ( 339 | private[this] final var _fun: Any => Any, 340 | private[this] final var _arg: AnyRef, 341 | private[this] final val _xform: Byte 342 | ) extends DefaultPromise[T]() with Callback[F] with Runnable with OnCompleteRunnable { 343 | def this(xform: Int, f: _ => _, ec: ExecutionContext) = this(f.asInstanceOf[Any => Any], ec.prepare(): AnyRef, xform.asInstanceOf[Byte]) 344 | 345 | // Gets invoked when a value is available, schedules it to be run():ed by the ExecutionContext 346 | // submitWithValue *happens-before* run(), through ExecutionContext.execute. 347 | // Invariant: _arg is `ExecutionContext` 348 | // requireNonNull(v) will hold as guarded by `resolve` 349 | final def submitWithValue(resolved: Try[F]): Unit = 350 | if (_fun ne null) { 351 | val executor = _arg.asInstanceOf[ExecutionContext] 352 | try { 353 | _arg = resolved 354 | executor.execute(this) // Safe publication of _arg = v (and _fun) 355 | } catch { 356 | case t if NonFatal(t) || t.isInstanceOf[InterruptedException] => 357 | handleSubmitFailure(t, executor) 358 | } 359 | } 360 | 361 | private[this] final def handleSubmitFailure(t: Throwable, e: ExecutionContext): Unit = { 362 | _fun = null // allow these to GC 363 | _arg = null 364 | val wasInterrupted = t.isInstanceOf[InterruptedException] 365 | if (wasInterrupted) Thread.currentThread.interrupt() 366 | if (!tryFailure(t) && !wasInterrupted) 367 | e.reportFailure(t) 368 | } 369 | 370 | // Gets invoked by the ExecutionContext, when we have a value to transform. 371 | // Invariant: if (_arg.isInstanceOf[Try[F]] && (_fun ne null)) 372 | override final def run(): Unit = 373 | try { 374 | val v = _arg.asInstanceOf[Try[F]] 375 | (_xform.asInstanceOf[Int]: @switch) match { 376 | case Xform_map => doMap(v) 377 | case Xform_flatMap => doFlatMap(v) 378 | case Xform_transform => doTransform(v) 379 | case Xform_transformWith => doTransformWith(v) 380 | case Xform_foreach => doForeach(v) 381 | case Xform_onComplete => doOnComplete(v) 382 | case Xform_recover => doRecover(v) 383 | case Xform_recoverWith => doRecoverWith(v) 384 | case Xform_filter => doFilter(v) 385 | case Xform_collect => doCollect(v) 386 | case _ => doAbort(v) 387 | } 388 | } catch { 389 | case t if NonFatal(t) || t.isInstanceOf[InterruptedException] => handleRunFailure(t) 390 | } finally { // allow these to GC 391 | _fun = null 392 | _arg = null 393 | } 394 | 395 | private[this] final def handleRunFailure(t: Throwable): Unit = { 396 | tryFailure(t) 397 | if (t.isInstanceOf[InterruptedException]) 398 | Thread.currentThread.interrupt() 399 | } 400 | 401 | override final def toString: String = super[DefaultPromise].toString 402 | 403 | private[this] final def completeFuture(f: Future[T]): Unit = 404 | if(f.isInstanceOf[DefaultPromise[T]]) f.asInstanceOf[DefaultPromise[T]].linkRootOf(this) 405 | else completeWith(f) 406 | 407 | private[this] final def doMap(v: Try[F]): Unit = tryComplete(v.map(_fun.asInstanceOf[F => T])) 408 | 409 | private[this] final def doFlatMap(v: Try[F]): Unit = 410 | if (v.isInstanceOf[Success[F]]) completeFuture(_fun(v.asInstanceOf[Success[F]].value).asInstanceOf[Future[T]]) 411 | else tryComplete(v.asInstanceOf[Try[T]]) 412 | 413 | private[this] final def doTransform(v: Try[F]): Unit = tryComplete(_fun(v).asInstanceOf[Try[T]]) 414 | 415 | private[this] final def doTransformWith(v: Try[F]): Unit = completeFuture(_fun(v).asInstanceOf[Future[T]]) 416 | 417 | private[this] final def doForeach(v: Try[F]): Unit = { 418 | v foreach _fun 419 | tryComplete(Future.successOfUnit.asInstanceOf[Try[T]]) // The results of this will never be observed. 420 | } 421 | 422 | private[this] final def doOnComplete(v: Try[F]): Unit = { 423 | _fun(v) 424 | tryComplete(Future.successOfUnit.asInstanceOf[Try[T]]) // The results of this will never be observed. 425 | } 426 | 427 | private[this] final def doRecover(v: Try[F]): Unit = 428 | tryComplete(v.recover(_fun.asInstanceOf[PartialFunction[Throwable, F]]).asInstanceOf[Try[T]]) //recover F=:=T 429 | 430 | private[this] final def doRecoverWith(v: Try[F]): Unit = //recoverWith F=:=T 431 | if (v.isInstanceOf[Failure[F]]) { 432 | val r = _fun.asInstanceOf[PartialFunction[Throwable, Future[T]]].applyOrElse(v.asInstanceOf[Failure[F]].exception, Future.recoverWithFailed) 433 | if (r ne Future.recoverWithFailedMarker) completeFuture(r) 434 | else tryComplete(v.asInstanceOf[Failure[T]]) 435 | } else tryComplete(v.asInstanceOf[Try[T]]) 436 | 437 | private[this] final def doFilter(v: Try[F]): Unit = 438 | tryComplete( 439 | if (v.isInstanceOf[Failure[F]] || _fun.asInstanceOf[F => Boolean](v.asInstanceOf[Success[F]].value)) v.asInstanceOf[Try[T]] 440 | else Future.filterFailure 441 | ) 442 | 443 | private[this] final def doCollect(v: Try[F]): Unit = 444 | tryComplete( 445 | if (v.isInstanceOf[Success[F]]) Success(_fun.asInstanceOf[PartialFunction[F, T]].applyOrElse(v.asInstanceOf[Success[F]].value, Future.collectFailed)) 446 | else v.asInstanceOf[Try[T]] 447 | ) 448 | 449 | private[this] final def doAbort(v: Try[F]): Unit = 450 | tryComplete(Failure(new IllegalStateException("BUG: encountered transformation promise with illegal type: " + _xform))) 451 | } 452 | } 453 | -------------------------------------------------------------------------------- /benches/src/main/scala/scala/future/Benchmarks.scala: -------------------------------------------------------------------------------- 1 | package scala.future 2 | 3 | import scala.concurrent.duration._ 4 | import java.util.concurrent.{ TimeUnit, Executor, Executors, ExecutorService, ForkJoinPool, CountDownLatch } 5 | import org.openjdk.jmh.infra.Blackhole 6 | import org.openjdk.jmh.annotations._ 7 | import scala.util.{ Try, Success, Failure } 8 | import scala.annotation.tailrec 9 | import scala.{concurrent => stdlib} 10 | import scala.{future => improved} 11 | 12 | @State(Scope.Benchmark) 13 | @BenchmarkMode(Array(Mode.Throughput)) 14 | @OutputTimeUnit(TimeUnit.MILLISECONDS) 15 | @Warmup(iterations = 1000) 16 | @Measurement(iterations = 10000) 17 | @Fork(value = 1, jvmArgsAppend = Array(/*"-agentpath:/Applications/YourKit-Java-Profiler-2017.02.app/Contents/Resources/bin/mac/libyjpagent.jnilib", */ "-Xmx512M", "-Xms512M", "-ea", "-server", "-XX:+UseCompressedOops", "-XX:+AlwaysPreTouch", "-XX:+UseCondCardMark")) 18 | @Threads(value = 1) 19 | abstract class AbstractBaseBenchmark { 20 | @Param(Array[String]("fjp", "fix", "fie")) 21 | final var pool: String = _ 22 | 23 | @Param(Array[String]("1")) 24 | final var threads: Int = _ 25 | 26 | @Param(Array[String]("1024")) 27 | final var recursion: Int = _ 28 | 29 | //@Param(Array[String]("success", "failure")) 30 | //final var status: String = _ 31 | 32 | final var executor: Executor = _ 33 | 34 | final var stdlibEC: stdlib.ExecutionContext = _ 35 | final var improvedEC: stdlib.ExecutionContext = _ 36 | 37 | final val timeout = 60.seconds 38 | 39 | @Setup(Level.Trial) 40 | def startup: Unit = { 41 | val (executorStdlib, executorImproved) = pool match { 42 | case "fjp" => 43 | val fjp = new ForkJoinPool(threads) 44 | executor = fjp 45 | (fjp, fjp) 46 | case "fix" => 47 | val ftp = Executors.newFixedThreadPool(threads) 48 | executor = ftp 49 | (ftp, ftp) 50 | case "gbl" => 51 | (stdlib.ExecutionContext.global, stdlib.ExecutionContext.global) 52 | case "fie" => 53 | (scala.concurrent.InternalCallbackExecutor().asInstanceOf[Executor], scala.future.Future.InternalCallbackExecutor) 54 | } 55 | 56 | stdlibEC = 57 | if (executorStdlib.isInstanceOf[stdlib.ExecutionContext]) executorStdlib.asInstanceOf[stdlib.ExecutionContext] 58 | else if (true) { 59 | new stdlib.ExecutionContext with stdlib.BatchingEC { 60 | private[this] final val g = executorStdlib 61 | override final def unbatchedExecute(r: Runnable) = g.execute(r) 62 | override final def reportFailure(t: Throwable) = t.printStackTrace(System.err) 63 | } 64 | } else { 65 | new stdlib.ExecutionContext { 66 | private[this] final val g = executorStdlib 67 | override final def execute(r: Runnable) = g.execute(r) 68 | override final def reportFailure(t: Throwable) = t.printStackTrace(System.err) 69 | } 70 | } 71 | 72 | improvedEC = 73 | if (executorImproved.isInstanceOf[stdlib.ExecutionContext]) executorImproved.asInstanceOf[stdlib.ExecutionContext] 74 | else if (true) { 75 | new stdlib.ExecutionContext with improved.BatchingExecutor { 76 | private[this] final val g = executorImproved 77 | override final def unbatchedExecute(r: Runnable) = g.execute(r) 78 | override final def reportFailure(t: Throwable) = t.printStackTrace(System.err) 79 | } 80 | } else { 81 | new stdlib.ExecutionContext { 82 | private[this] final val g = executorImproved 83 | override final def execute(r: Runnable) = g.execute(r) 84 | override final def reportFailure(t: Throwable) = t.printStackTrace(System.err) 85 | } 86 | } 87 | } 88 | 89 | @TearDown(Level.Trial) 90 | final def shutdown: Unit = { 91 | executor = executor match { 92 | case es: ExecutorService => 93 | try es.shutdown() finally es.awaitTermination(1, TimeUnit.MINUTES) 94 | null 95 | case _ => null 96 | } 97 | } 98 | } 99 | 100 | abstract class OpBenchmark extends AbstractBaseBenchmark { 101 | type Result = String 102 | 103 | final val stdlibFailure = Failure(new Exception("stdlib")) 104 | final val improvedFailure = Failure(new Exception("improved")) 105 | 106 | final val stdlibSuccess = Success("stdlib") 107 | final val improvedSuccess = Success("improved") 108 | 109 | final val improved_pre_s_p: improved.Promise[Result] = improved.Promise.fromTry(improvedSuccess) 110 | final val stdlib_pre_s_p: stdlib.Promise[Result] = stdlib.Promise.fromTry(stdlibSuccess) 111 | 112 | final val improved_pre_f_p: improved.Promise[Result] = improved.Promise.fromTry(improvedFailure) 113 | final val stdlib_pre_f_p: stdlib.Promise[Result] = stdlib.Promise.fromTry(stdlibFailure) 114 | 115 | final var stdlibResult: Try[Result] = _ 116 | final var improvedResult: Try[Result] = _ 117 | 118 | override def startup: Unit = { 119 | super.startup 120 | /*stdlibResult = status match { 121 | case "success" => stdlibSuccess 122 | case "failure" => stdlibFailure 123 | } 124 | 125 | improvedResult = status match { 126 | case "success" => improvedSuccess 127 | case "failure" => improvedFailure 128 | }*/ 129 | } 130 | 131 | protected final def await[T](a: stdlib.Future[T]): Boolean = { 132 | var r: Option[Try[T]] = None 133 | do { 134 | r = a.value 135 | } while(r eq None); 136 | r.get.isInstanceOf[Success[T]] 137 | } 138 | 139 | protected final def await[T](a: improved.Future[T]): Boolean = { 140 | var r: Option[Try[T]] = None 141 | do { 142 | r = a.value 143 | } while(r eq None); 144 | r.get.isInstanceOf[Success[T]] 145 | } 146 | } 147 | 148 | class NoopBenchmark extends OpBenchmark { 149 | @tailrec private[this] final def nextS(i: Int, bh: Blackhole,f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 150 | if (i > 0) { nextS(i - 1, bh, f) } else { bh.consume(f); f } 151 | 152 | @tailrec private[this] final def nextI(i: Int, bh: Blackhole,f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 153 | if (i > 0) { nextI(i - 1, bh, f) } else { bh.consume(f); f } 154 | 155 | @Benchmark final def stdlib_pre(bh: Blackhole): Boolean = 156 | await(nextS(recursion, bh, stdlib_pre_s_p.future)(stdlibEC)) 157 | 158 | @Benchmark final def stdlib_post(bh: Blackhole): Boolean = { 159 | val stdlib_post_p = stdlib.Promise[Result]() 160 | val f = nextS(recursion, bh, stdlib_post_p.future)(stdlibEC) 161 | stdlib_post_p.complete(stdlibSuccess) 162 | await(f) 163 | } 164 | 165 | @Benchmark final def improved_pre(bh: Blackhole): Boolean = { 166 | await(nextI(recursion, bh, improved_pre_s_p.future)(improvedEC)) 167 | } 168 | 169 | @Benchmark final def improved_post(bh: Blackhole): Boolean = { 170 | val improved_post_p = improved.Promise[Result]() 171 | val f = nextI(recursion, bh, improved_post_p.future)(improvedEC) 172 | improved_post_p.complete(improvedSuccess) 173 | await(f) 174 | } 175 | } 176 | 177 | class MapBenchmark extends OpBenchmark { 178 | final val transformationFun = (r: Result) => r 179 | 180 | @tailrec private[this] final def nextS(i: Int, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 181 | if (i > 0) { nextS(i - 1, f.map(transformationFun)) } else { f } 182 | 183 | @tailrec private[this] final def nextI(i: Int, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 184 | if (i > 0) { nextI(i - 1, f.map(transformationFun)) } else { f } 185 | 186 | @Benchmark final def stdlib_pre(): Boolean = 187 | await(nextS(recursion, stdlib_pre_s_p.future)(stdlibEC)) 188 | 189 | @Benchmark final def stdlib_post(): Boolean = { 190 | val stdlib_post_p = stdlib.Promise[Result]() 191 | val f = nextS(recursion, stdlib_post_p.future)(stdlibEC) 192 | stdlib_post_p.complete(stdlibSuccess) 193 | await(f) 194 | } 195 | 196 | @Benchmark final def improved_pre(): Boolean = { 197 | await(nextI(recursion, improved_pre_s_p.future)(improvedEC)) 198 | } 199 | 200 | @Benchmark final def improved_post(): Boolean = { 201 | val improved_post_p = improved.Promise[Result]() 202 | val f = nextI(recursion, improved_post_p.future)(improvedEC) 203 | improved_post_p.complete(improvedSuccess) 204 | await(f) 205 | } 206 | } 207 | 208 | class FilterBenchmark extends OpBenchmark { 209 | final val transformationFun = (r: Result) => true 210 | 211 | @tailrec private[this] final def nextS(i: Int, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 212 | if (i > 0) { nextS(i - 1, f.filter(transformationFun)) } else { f } 213 | 214 | @tailrec private[this] final def nextI(i: Int, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 215 | if (i > 0) { nextI(i - 1, f.filter(transformationFun)) } else { f } 216 | 217 | @Benchmark final def stdlib_pre(): Boolean = 218 | await(nextS(recursion, stdlib_pre_s_p.future)(stdlibEC)) 219 | 220 | @Benchmark final def stdlib_post(): Boolean = { 221 | val stdlib_post_p = stdlib.Promise[Result]() 222 | val f = nextS(recursion, stdlib_post_p.future)(stdlibEC) 223 | stdlib_post_p.complete(stdlibSuccess) 224 | await(f) 225 | } 226 | 227 | @Benchmark final def improved_pre(): Boolean = { 228 | await(nextI(recursion, improved_pre_s_p.future)(improvedEC)) 229 | } 230 | 231 | @Benchmark final def improved_post(): Boolean = { 232 | val improved_post_p = improved.Promise[Result]() 233 | val f = nextI(recursion, improved_post_p.future)(improvedEC) 234 | improved_post_p.complete(improvedSuccess) 235 | await(f) 236 | } 237 | } 238 | 239 | class TransformBenchmark extends OpBenchmark { 240 | final val transformationFun = (t: Try[Result]) => t 241 | 242 | @tailrec private[this] final def nextS(i: Int, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 243 | if (i > 0) { nextS(i - 1, f.transform(transformationFun)) } else { f } 244 | 245 | @tailrec private[this] final def nextI(i: Int, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 246 | if (i > 0) { nextI(i - 1, f.transform(transformationFun)) } else { f } 247 | 248 | @Benchmark final def stdlib_pre(): Boolean = 249 | await(nextS(recursion, stdlib_pre_s_p.future)(stdlibEC)) 250 | 251 | @Benchmark final def stdlib_post(): Boolean = { 252 | val stdlib_post_p = stdlib.Promise[Result]() 253 | val f = nextS(recursion, stdlib_post_p.future)(stdlibEC) 254 | stdlib_post_p.complete(stdlibSuccess) 255 | await(f) 256 | } 257 | 258 | @Benchmark final def improved_pre(): Boolean = { 259 | await(nextI(recursion, improved_pre_s_p.future)(improvedEC)) 260 | } 261 | 262 | @Benchmark final def improved_post(): Boolean = { 263 | val improved_post_p = improved.Promise[Result]() 264 | val f = nextI(recursion, improved_post_p.future)(improvedEC) 265 | improved_post_p.complete(improvedSuccess) 266 | await(f) 267 | } 268 | } 269 | 270 | class TransformWithBenchmark extends OpBenchmark { 271 | final val transformationFunStdlib = (t: Try[Result]) => stdlib.Future.fromTry(t) 272 | final val transformationFunImproved = (t: Try[Result]) => improved.Future.fromTry(t) 273 | 274 | @tailrec private[this] final def nextS(i: Int, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 275 | if (i > 0) { nextS(i - 1, f.transformWith(transformationFunStdlib)) } else { f } 276 | 277 | @tailrec private[this] final def nextI(i: Int, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 278 | if (i > 0) { nextI(i - 1, f.transformWith(transformationFunImproved)) } else { f } 279 | 280 | @Benchmark final def stdlib_pre(): Boolean = 281 | await(nextS(recursion, stdlib_pre_s_p.future)(stdlibEC)) 282 | 283 | @Benchmark final def stdlib_post(): Boolean = { 284 | val stdlib_post_p = stdlib.Promise[Result]() 285 | val f = nextS(recursion, stdlib_post_p.future)(stdlibEC) 286 | stdlib_post_p.complete(stdlibSuccess) 287 | await(f) 288 | } 289 | 290 | @Benchmark final def improved_pre(): Boolean = { 291 | await(nextI(recursion, improved_pre_s_p.future)(improvedEC)) 292 | } 293 | 294 | @Benchmark final def improved_post(): Boolean = { 295 | val improved_post_p = improved.Promise[Result]() 296 | val f = nextI(recursion, improved_post_p.future)(improvedEC) 297 | improved_post_p.complete(improvedSuccess) 298 | await(f) 299 | } 300 | } 301 | 302 | class FlatMapBenchmark extends OpBenchmark { 303 | final val transformationFunStdlib = (t: Result) => stdlib.Future.successful(t) 304 | final val transformationFunImproved = (t: Result) => improved.Future.successful(t) 305 | 306 | @tailrec private[this] final def nextS(i: Int, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 307 | if (i > 0) { nextS(i - 1, f.flatMap(transformationFunStdlib)) } else { f } 308 | 309 | @tailrec private[this] final def nextI(i: Int, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 310 | if (i > 0) { nextI(i - 1, f.flatMap(transformationFunImproved)) } else { f } 311 | 312 | @Benchmark final def stdlib_pre(): Boolean = 313 | await(nextS(recursion, stdlib_pre_s_p.future)(stdlibEC)) 314 | 315 | @Benchmark final def stdlib_post(): Boolean = { 316 | val stdlib_post_p = stdlib.Promise[Result]() 317 | val f = nextS(recursion, stdlib_post_p.future)(stdlibEC) 318 | stdlib_post_p.complete(stdlibSuccess) 319 | await(f) 320 | } 321 | 322 | @Benchmark final def improved_pre(): Boolean = { 323 | await(nextI(recursion, improved_pre_s_p.future)(improvedEC)) 324 | } 325 | 326 | @Benchmark final def improved_post(): Boolean = { 327 | val improved_post_p = improved.Promise[Result]() 328 | val f = nextI(recursion, improved_post_p.future)(improvedEC) 329 | improved_post_p.complete(improvedSuccess) 330 | await(f) 331 | } 332 | } 333 | 334 | class RecoverBenchmark extends OpBenchmark { 335 | final val recoverFunStdlib: PartialFunction[Throwable, Result] = { case _ => stdlibFailure.get } 336 | final val recoverFunImproved: PartialFunction[Throwable, Result] = { case _ => improvedFailure.get } 337 | 338 | @tailrec private[this] final def nextS(i: Int, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 339 | if (i > 0) { nextS(i - 1, f.recover(recoverFunStdlib)) } else { f } 340 | 341 | @tailrec private[this] final def nextI(i: Int, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 342 | if (i > 0) { nextI(i - 1, f.recover(recoverFunImproved)) } else { f } 343 | 344 | @Benchmark final def stdlib_pre(): Boolean = 345 | await(nextS(recursion, stdlib_pre_f_p.future)(stdlibEC)) 346 | 347 | @Benchmark final def stdlib_post(): Boolean = { 348 | val stdlib_post_p = stdlib.Promise[Result]() 349 | val f = nextS(recursion, stdlib_post_p.future)(stdlibEC) 350 | stdlib_post_p.complete(stdlibFailure) 351 | await(f) 352 | } 353 | 354 | @Benchmark final def improved_pre(): Boolean = { 355 | await(nextI(recursion, improved_pre_f_p.future)(improvedEC)) 356 | } 357 | 358 | @Benchmark final def improved_post(): Boolean = { 359 | val improved_post_p = improved.Promise[Result]() 360 | val f = nextI(recursion, improved_post_p.future)(improvedEC) 361 | improved_post_p.complete(improvedFailure) 362 | await(f) 363 | } 364 | } 365 | 366 | class RecoverWithBenchmark extends OpBenchmark { 367 | final val recoverWithFunStdlib: PartialFunction[Throwable, stdlib.Future[Result]] = { case _ => stdlib_pre_f_p.future } 368 | final val recoverWithFunImproved: PartialFunction[Throwable, improved.Future[Result]] = { case _ => improved_pre_f_p.future } 369 | 370 | @tailrec private[this] final def nextS(i: Int, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 371 | if (i > 0) { nextS(i - 1, f.recoverWith(recoverWithFunStdlib)) } else { f } 372 | 373 | @tailrec private[this] final def nextI(i: Int, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 374 | if (i > 0) { nextI(i - 1, f.recoverWith(recoverWithFunImproved)) } else { f } 375 | 376 | @Benchmark final def stdlib_pre(): Boolean = 377 | await(nextS(recursion, stdlib_pre_f_p.future)(stdlibEC)) 378 | 379 | @Benchmark final def stdlib_post(): Boolean = { 380 | val stdlib_post_p = stdlib.Promise[Result]() 381 | val f = nextS(recursion, stdlib_post_p.future)(stdlibEC) 382 | stdlib_post_p.complete(stdlibFailure) 383 | await(f) 384 | } 385 | 386 | @Benchmark final def improved_pre(): Boolean = { 387 | await(nextI(recursion, improved_pre_f_p.future)(improvedEC)) 388 | } 389 | 390 | @Benchmark final def improved_post(): Boolean = { 391 | val improved_post_p = improved.Promise[Result]() 392 | val f = nextI(recursion, improved_post_p.future)(improvedEC) 393 | improved_post_p.complete(improvedFailure) 394 | await(f) 395 | } 396 | } 397 | 398 | 399 | class ZipWithBenchmark extends OpBenchmark { 400 | final val transformationFun = (t1: Result, t2: Result) => t2 401 | 402 | @tailrec private[this] final def nextS(i: Int, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 403 | if (i > 0) { nextS(i - 1, f.zipWith(f)(transformationFun)) } else { f } 404 | 405 | @tailrec private[this] final def nextI(i: Int, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 406 | if (i > 0) { nextI(i - 1, f.zipWith(f)(transformationFun)) } else { f } 407 | 408 | @Benchmark final def stdlib_pre(): Boolean = 409 | await(nextS(recursion, stdlib_pre_s_p.future)(stdlibEC)) 410 | 411 | @Benchmark final def stdlib_post(): Boolean = { 412 | val stdlib_post_p = stdlib.Promise[Result]() 413 | val f = nextS(recursion, stdlib_post_p.future)(stdlibEC) 414 | stdlib_post_p.complete(stdlibSuccess) 415 | await(f) 416 | } 417 | 418 | @Benchmark final def improved_pre(): Boolean = { 419 | await(nextI(recursion, improved_pre_s_p.future)(improvedEC)) 420 | } 421 | 422 | @Benchmark final def improved_post(): Boolean = { 423 | val improved_post_p = improved.Promise[Result]() 424 | val f = nextI(recursion, improved_post_p.future)(improvedEC) 425 | improved_post_p.complete(improvedSuccess) 426 | await(f) 427 | } 428 | } 429 | 430 | class AndThenBenchmark extends OpBenchmark { 431 | final val effect: PartialFunction[Try[Result], Unit] = { case t: Try[Result] => () } 432 | 433 | @tailrec private[this] final def nextS(i: Int, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 434 | if (i > 0) { nextS(i - 1, f.andThen(effect)) } else { f } 435 | 436 | @tailrec private[this] final def nextI(i: Int, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 437 | if (i > 0) { nextI(i - 1, f.andThen(effect)) } else { f } 438 | 439 | @Benchmark final def stdlib_pre(): Boolean = 440 | await(nextS(recursion, stdlib_pre_s_p.future)(stdlibEC)) 441 | 442 | @Benchmark final def stdlib_post(): Boolean = { 443 | val stdlib_post_p = stdlib.Promise[Result]() 444 | val f = nextS(recursion, stdlib_post_p.future)(stdlibEC) 445 | stdlib_post_p.complete(stdlibSuccess) 446 | await(f) 447 | } 448 | 449 | @Benchmark final def improved_pre(): Boolean = { 450 | await(nextI(recursion, improved_pre_s_p.future)(improvedEC)) 451 | } 452 | 453 | @Benchmark final def improved_post(): Boolean = { 454 | val improved_post_p = improved.Promise[Result]() 455 | val f = nextI(recursion, improved_post_p.future)(improvedEC) 456 | improved_post_p.complete(improvedSuccess) 457 | await(f) 458 | } 459 | } 460 | 461 | class VariousBenchmark extends OpBenchmark { 462 | final val mapFun: Result => Result = _.toUpperCase 463 | final val stdlibFlatMapFun: Result => stdlib.Future[Result] = r => stdlib.Future.successful(r) 464 | final val improvedFlatMapFun: Result => improved.Future[Result] = r => improved.Future.successful(r) 465 | final val filterFun: Result => Boolean = _ ne null 466 | final val transformFun: Try[Result] => Try[Result] = _ => throw null 467 | final val recoverFun: PartialFunction[Throwable, Result] = { case _ => "OK" } 468 | final val keepLeft: (Result, Result) => Result = (a,b) => a 469 | 470 | @tailrec private[this] final def nextS(i: Int, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 471 | if (i > 0) { nextS(i - 1, f.map(mapFun).flatMap(stdlibFlatMapFun).filter(filterFun).zipWith(f)(keepLeft).transform(transformFun).recover(recoverFun)) } else { f } 472 | 473 | @tailrec private[this] final def nextI(i: Int, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 474 | if (i > 0) { nextI(i - 1, f.map(mapFun).flatMap(improvedFlatMapFun).filter(filterFun).zipWith(f)(keepLeft).transform(transformFun).recover(recoverFun)) } else { f } 475 | 476 | @Benchmark final def stdlib_pre(): Boolean = 477 | await(nextS(recursion, stdlib_pre_s_p.future)(stdlibEC)) 478 | 479 | @Benchmark final def stdlib_post(): Boolean = { 480 | val stdlib_post_p = stdlib.Promise[Result]() 481 | val f = nextS(recursion, stdlib_post_p.future)(stdlibEC) 482 | stdlib_post_p.complete(stdlibSuccess) 483 | await(f) 484 | } 485 | 486 | @Benchmark final def improved_pre(): Boolean = { 487 | await(nextI(recursion, improved_pre_s_p.future)(improvedEC)) 488 | } 489 | 490 | @Benchmark final def improved_post(): Boolean = { 491 | val improved_post_p = improved.Promise[Result]() 492 | val f = nextI(recursion, improved_post_p.future)(improvedEC) 493 | improved_post_p.complete(improvedSuccess) 494 | await(f) 495 | } 496 | } 497 | 498 | class LoopBenchmark extends OpBenchmark { 499 | val depth = 50 500 | val size = 2000 501 | 502 | def pre_stdlib_loop(i: Int)(implicit ec: stdlib.ExecutionContext): stdlib.Future[Int] = 503 | if (i % depth == 0) stdlib.Future.successful(i + 1).flatMap(pre_stdlib_loop) 504 | else if (i < size) pre_stdlib_loop(i + 1).flatMap(stdlib.Future.successful) 505 | else stdlib.Future.successful(i) 506 | 507 | def pre_improved_loop(i: Int)(implicit ec: stdlib.ExecutionContext): improved.Future[Int] = 508 | if (i % depth == 0) improved.Future.successful(i + 1).flatMap(pre_improved_loop) 509 | else if (i < size) pre_improved_loop(i + 1).flatMap(improved.Future.successful) 510 | else improved.Future.successful(i) 511 | 512 | def post_stdlib_loop(i: Int)(implicit ec: stdlib.ExecutionContext): stdlib.Future[Int] = 513 | if (i % depth == 0) stdlib.Future(i + 1).flatMap(post_stdlib_loop) 514 | else if (i < size) post_stdlib_loop(i + 1).flatMap(i => stdlib.Future(i)) 515 | else stdlib.Future(i) 516 | 517 | def post_improved_loop(i: Int)(implicit ec: stdlib.ExecutionContext): improved.Future[Int] = 518 | if (i % depth == 0) improved.Future(i + 1).flatMap(post_improved_loop) 519 | else if (i < size) post_improved_loop(i + 1).flatMap(i => improved.Future(i)) 520 | else improved.Future(i) 521 | 522 | 523 | @Benchmark final def stdlib_pre(): Boolean = { 524 | implicit val ec = stdlibEC 525 | await(stdlib_pre_s_p.future.flatMap(s => pre_stdlib_loop(recursion).map(_ => s))) 526 | } 527 | 528 | @Benchmark final def stdlib_post(): Boolean = { 529 | implicit val ec = stdlibEC 530 | val stdlib_post_p = stdlib.Promise[Result]() 531 | val f = stdlib_post_p.future.flatMap(s => post_stdlib_loop(recursion).map(_ => s)) 532 | stdlib_post_p.complete(stdlibSuccess) 533 | await(f) 534 | } 535 | 536 | @Benchmark final def improved_pre(): Boolean = { 537 | implicit val ec = improvedEC 538 | await(improved_pre_s_p.future.flatMap(s => pre_improved_loop(recursion).map(_ => s))) 539 | } 540 | 541 | @Benchmark final def improved_post(): Boolean = { 542 | implicit val ec = improvedEC 543 | val improved_post_p = improved.Promise[Result]() 544 | val f = improved_post_p.future.flatMap(s => post_improved_loop(recursion).map(_ => s)) 545 | improved_post_p.complete(improvedSuccess) 546 | await(f) 547 | } 548 | } 549 | 550 | class SequenceBenchmark extends OpBenchmark { 551 | 552 | @Benchmark final def stdlib_pre(): Boolean = { 553 | implicit val ec = stdlibEC 554 | await(stdlib.Future.sequence(1 to recursion map { _ => stdlib_pre_s_p.future })) 555 | } 556 | 557 | @Benchmark final def stdlib_post(): Boolean = { 558 | implicit val ec = stdlibEC 559 | val stdlib_post_p = stdlib.Promise[Result]() 560 | val f = stdlib.Future.sequence(1 to recursion map { _ => stdlib_post_p.future }) 561 | stdlib_post_p.complete(stdlibSuccess) 562 | await(f) 563 | } 564 | 565 | @Benchmark final def improved_pre(): Boolean = { 566 | implicit val ec = improvedEC 567 | await(improved.Future.sequence(1 to recursion map { _ => improved_pre_s_p.future })) 568 | } 569 | 570 | @Benchmark final def improved_post(): Boolean = { 571 | implicit val ec = improvedEC 572 | val improved_post_p = improved.Promise[Result]() 573 | val f = improved.Future.sequence(1 to recursion map { _ => improved_post_p.future }) 574 | improved_post_p.complete(improvedSuccess) 575 | await(f) 576 | } 577 | } 578 | 579 | class FirstCompletedOfBenchmark extends OpBenchmark { 580 | 581 | @Benchmark final def stdlib_pre(): Boolean = { 582 | implicit val ec = stdlibEC 583 | await(stdlib.Future.firstCompletedOf(1 to recursion map { _ => stdlib_pre_s_p.future })) 584 | } 585 | 586 | @Benchmark final def stdlib_post(): Boolean = { 587 | implicit val ec = stdlibEC 588 | val stdlib_post_p = stdlib.Promise[Result]() 589 | val f = stdlib.Future.firstCompletedOf(1 to recursion map { _ => stdlib_post_p.future }) 590 | stdlib_post_p.complete(stdlibSuccess) 591 | await(f) 592 | } 593 | 594 | @Benchmark final def improved_pre(): Boolean = { 595 | implicit val ec = improvedEC 596 | await(improved.Future.firstCompletedOf(1 to recursion map { _ => improved_pre_s_p.future })) 597 | } 598 | 599 | @Benchmark final def improved_post(): Boolean = { 600 | implicit val ec = improvedEC 601 | val improved_post_p = improved.Promise[Result]() 602 | val f = improved.Future.firstCompletedOf(1 to recursion map { _ => improved_post_p.future }) 603 | improved_post_p.complete(improvedSuccess) 604 | await(f) 605 | } 606 | } 607 | 608 | class CompleteBenchmark extends OpBenchmark { 609 | 610 | @tailrec private[this] final def nextS(i: Int, p: stdlib.Promise[Result], r: Try[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 611 | if (i > 0) { nextS(i - 1, { p.tryComplete(r); p }, r) } else { p.future } 612 | 613 | @tailrec private[this] final def nextI(i: Int, p: improved.Promise[Result], r: Try[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 614 | if (i > 0) { nextI(i - 1, { p.tryComplete(r); p }, r) } else { p.future } 615 | 616 | @Benchmark final def stdlib_success(): Boolean = { 617 | val f = nextS(recursion, stdlib.Promise[Result](), stdlibSuccess)(stdlibEC) 618 | await(f) 619 | } 620 | 621 | @Benchmark final def improved_success(): Boolean = { 622 | val f = nextI(recursion, improved.Promise[Result](), improvedSuccess)(improvedEC) 623 | await(f) 624 | } 625 | 626 | @Benchmark final def stdlib_failure(): Boolean = { 627 | val f = nextS(recursion, stdlib.Promise[Result](), stdlibFailure)(stdlibEC) 628 | await(f) 629 | } 630 | 631 | @Benchmark final def improved_failure(): Boolean = { 632 | val f = nextI(recursion, improved.Promise[Result](), improvedFailure)(improvedEC) 633 | await(f) 634 | } 635 | } 636 | 637 | class CompleteWithBenchmark extends OpBenchmark { 638 | 639 | @tailrec private[this] final def nextS(i: Int, p: stdlib.Promise[Result], f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 640 | if (i > 0) { nextS(i - 1, { p.tryCompleteWith(f); p }, f) } else { p.future } 641 | 642 | @tailrec private[this] final def nextI(i: Int, p: improved.Promise[Result], f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 643 | if (i > 0) { nextI(i - 1, { p.tryCompleteWith(f); p }, f) } else { p.future } 644 | 645 | @Benchmark final def stdlib_success(): Boolean = { 646 | val f = nextS(recursion, stdlib.Promise[Result](), stdlib_pre_s_p.future)(stdlibEC) 647 | await(f) 648 | } 649 | 650 | @Benchmark final def improved_success(): Boolean = { 651 | val f = nextI(recursion, improved.Promise[Result](), improved_pre_s_p.future)(improvedEC) 652 | await(f) 653 | } 654 | 655 | @Benchmark final def stdlib_failure(): Boolean = { 656 | val f = nextS(recursion, stdlib.Promise[Result](), stdlib_pre_f_p.future)(stdlibEC) 657 | await(f) 658 | } 659 | 660 | @Benchmark final def improved_failure(): Boolean = { 661 | val f = nextI(recursion, improved.Promise[Result](), improved_pre_f_p.future)(improvedEC) 662 | await(f) 663 | } 664 | } 665 | 666 | class CallbackBenchmark extends OpBenchmark { 667 | class Callback(recursion: Int) extends CountDownLatch(recursion) with Function1[Try[Result], Unit] { 668 | override def apply(t:Try[Result]): Unit = this.countDown() 669 | } 670 | 671 | @tailrec private[this] final def nextS(i: Int, callback: Callback, f: stdlib.Future[Result])(implicit ec: stdlib.ExecutionContext): stdlib.Future[Result] = 672 | if (i > 0) { nextS(i - 1, callback, { f.onComplete(callback); f }) } else { f } 673 | 674 | @tailrec private[this] final def nextI(i: Int, callback: Callback, f: improved.Future[Result])(implicit ec: stdlib.ExecutionContext): improved.Future[Result] = 675 | if (i > 0) { nextI(i - 1, callback, { f.onComplete(callback); f }) } else { f } 676 | 677 | @Benchmark final def stdlib_pre(): Unit = { 678 | val callback = new Callback(recursion) 679 | nextS(recursion, callback, stdlib_pre_s_p.future)(stdlibEC) 680 | callback.await() 681 | } 682 | 683 | @Benchmark final def stdlib_post(): Unit = { 684 | val stdlib_post_p = stdlib.Promise[Result]() 685 | val callback = new Callback(recursion) 686 | nextS(recursion, callback, stdlib_post_p.future)(stdlibEC) 687 | stdlib_post_p.complete(stdlibSuccess) 688 | callback.await() 689 | } 690 | 691 | @Benchmark final def improved_pre(): Unit = { 692 | val callback = new Callback(recursion) 693 | nextI(recursion, callback,improved_pre_s_p.future)(improvedEC) 694 | callback.await() 695 | } 696 | 697 | @Benchmark final def improved_post(): Unit = { 698 | val improved_post_p = improved.Promise[Result]() 699 | val callback = new Callback(recursion) 700 | nextI(recursion, callback, improved_post_p.future)(improvedEC) 701 | improved_post_p.complete(improvedSuccess) 702 | callback.await() 703 | } 704 | } -------------------------------------------------------------------------------- /src/main/scala/scala/future/Future.scala: -------------------------------------------------------------------------------- 1 | /* __ *\ 2 | ** ________ ___ / / ___ Scala API ** 3 | ** / __/ __// _ | / / / _ | (c) 2003-2013, LAMP/EPFL ** 4 | ** __\ \/ /__/ __ |/ /__/ __ | http://scala-lang.org/ ** 5 | ** /____/\___/_/ |_/____/_/ | | ** 6 | ** |/ ** 7 | \* */ 8 | 9 | package scala.future 10 | 11 | import scala.language.higherKinds 12 | import scala.concurrent.{ExecutionContext, Awaitable, CanAwait} 13 | 14 | import java.util.concurrent.{CountDownLatch, TimeUnit, TimeoutException} 15 | import java.util.concurrent.atomic.{AtomicInteger, AtomicReference} 16 | 17 | import scala.util.control.{NonFatal, NoStackTrace} 18 | import scala.util.{Try, Success, Failure} 19 | import scala.concurrent.duration._ 20 | import scala.collection.mutable.Builder 21 | import scala.collection.generic.CanBuildFrom 22 | import scala.reflect.ClassTag 23 | 24 | /** A `Future` represents a value which may or may not *currently* be available, 25 | * but will be available at some point, or an exception if that value could not be made available. 26 | * 27 | * Asynchronous computations that yield futures are created with the `Future.apply` call and are computed using a supplied `ExecutionContext`, 28 | * which can be backed by a Thread pool. 29 | * 30 | * {{{ 31 | * import ExecutionContext.Implicits.global 32 | * val s = "Hello" 33 | * val f: Future[String] = Future { 34 | * s + " future!" 35 | * } 36 | * f foreach { 37 | * msg => println(msg) 38 | * } 39 | * }}} 40 | * 41 | * @author Philipp Haller, Heather Miller, Aleksandar Prokopec, Viktor Klang 42 | * 43 | * @see [[http://docs.scala-lang.org/overviews/core/futures.html Futures and Promises]] 44 | * 45 | * @define multipleCallbacks 46 | * Multiple callbacks may be registered; there is no guarantee that they will be 47 | * executed in a particular order. 48 | * 49 | * @define caughtThrowables 50 | * This future may contain a throwable object and this means that the future failed. 51 | * Futures obtained through combinators have the same exception as the future they were obtained from. 52 | * The following throwable objects are not contained in the future: 53 | * - `Error` - errors are not contained within futures 54 | * - `InterruptedException` - not contained within futures 55 | * - all `scala.util.control.ControlThrowable` except `NonLocalReturnControl` - not contained within futures 56 | * 57 | * Instead, the future is completed with a ExecutionException with one of the exceptions above 58 | * as the cause. 59 | * If a future is failed with a `scala.runtime.NonLocalReturnControl`, 60 | * it is completed with a value from that throwable instead. 61 | * 62 | * @define swallowsExceptions 63 | * Since this method executes asynchronously and does not produce a return value, 64 | * any non-fatal exceptions thrown will be reported to the `ExecutionContext`. 65 | * 66 | * @define nonDeterministic 67 | * Note: using this method yields nondeterministic dataflow programs. 68 | * 69 | * @define forComprehensionExamples 70 | * Example: 71 | * 72 | * {{{ 73 | * val f = Future { 5 } 74 | * val g = Future { 3 } 75 | * val h = for { 76 | * x: Int <- f // returns Future(5) 77 | * y: Int <- g // returns Future(3) 78 | * } yield x + y 79 | * }}} 80 | * 81 | * is translated to: 82 | * 83 | * {{{ 84 | * f flatMap { (x: Int) => g map { (y: Int) => x + y } } 85 | * }}} 86 | * 87 | * @define callbackInContext 88 | * The provided callback always runs in the provided implicit 89 | *`ExecutionContext`, though there is no guarantee that the 90 | * `execute()` method on the `ExecutionContext` will be called once 91 | * per callback or that `execute()` will be called in the current 92 | * thread. That is, the implementation may run multiple callbacks 93 | * in a batch within a single `execute()` and it may run 94 | * `execute()` either immediately or asynchronously. 95 | * Completion of the Future must *happen-before* the invocation of the callback. 96 | */ 97 | trait Future[+T] extends Awaitable[T] { 98 | import Future.{ InternalCallbackExecutor => internalExecutor } 99 | 100 | /* Callbacks */ 101 | 102 | /** When this future is completed successfully (i.e., with a value), 103 | * apply the provided partial function to the value if the partial function 104 | * is defined at that value. 105 | * 106 | * If the future has already been completed with a value, 107 | * this will either be applied immediately or be scheduled asynchronously. 108 | * 109 | * Note that the returned value of `pf` will be discarded. 110 | * 111 | * $swallowsExceptions 112 | * $multipleCallbacks 113 | * $callbackInContext 114 | * 115 | * @group Callbacks 116 | */ 117 | @deprecated("use `foreach` or `onComplete` instead (keep in mind that they take total rather than partial functions)", "2.12.0") 118 | def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit = onComplete { 119 | t => if (t.isInstanceOf[Success[T]]) pf.applyOrElse[T, Any](t.asInstanceOf[Success[T]].value, Future.id[T]) 120 | } 121 | 122 | /** When this future is completed with a failure (i.e., with a throwable), 123 | * apply the provided callback to the throwable. 124 | * 125 | * $caughtThrowables 126 | * 127 | * If the future has already been completed with a failure, 128 | * this will either be applied immediately or be scheduled asynchronously. 129 | * 130 | * Will not be called in case that the future is completed with a value. 131 | * 132 | * Note that the returned value of `pf` will be discarded. 133 | * 134 | * $swallowsExceptions 135 | * $multipleCallbacks 136 | * $callbackInContext 137 | * 138 | * @group Callbacks 139 | */ 140 | @deprecated("use `onComplete` or `failed.foreach` instead (keep in mind that they take total rather than partial functions)", "2.12.0") 141 | def onFailure[U](@deprecatedName('callback) pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = onComplete { 142 | t => if(t.isInstanceOf[Failure[T]]) pf.applyOrElse[Throwable, Any](t.asInstanceOf[Failure[T]].exception, Future.id[Throwable]) 143 | } 144 | 145 | /** When this future is completed, either through an exception, or a value, 146 | * apply the provided function. 147 | * 148 | * If the future has already been completed, 149 | * this will either be applied immediately or be scheduled asynchronously. 150 | * 151 | * Note that the returned value of `f` will be discarded. 152 | * 153 | * $swallowsExceptions 154 | * $multipleCallbacks 155 | * $callbackInContext 156 | * 157 | * @tparam U only used to accept any return type of the given callback function 158 | * @param f the function to be executed when this `Future` completes 159 | * @group Callbacks 160 | */ 161 | def onComplete[U](@deprecatedName('func) f: Try[T] => U)(implicit executor: ExecutionContext): Unit 162 | 163 | 164 | /* Miscellaneous */ 165 | 166 | /** Returns whether the future had already been completed with 167 | * a value or an exception. 168 | * 169 | * $nonDeterministic 170 | * 171 | * @return `true` if the future was completed, `false` otherwise 172 | * @group Polling 173 | */ 174 | def isCompleted: Boolean 175 | 176 | /** The current value of this `Future`. 177 | * 178 | * $nonDeterministic 179 | * 180 | * If the future was not completed the returned value will be `None`. 181 | * If the future was completed the value will be `Some(Success(t))` 182 | * if it contained a valid result, or `Some(Failure(error))` if it contained 183 | * an exception. 184 | * 185 | * @return `None` if the `Future` wasn't completed, `Some` if it was. 186 | * @group Polling 187 | */ 188 | def value: Option[Try[T]] 189 | 190 | 191 | /* Projections */ 192 | 193 | /** The returned `Future` will be successfully completed with the `Throwable` of the original `Future` 194 | * if the original `Future` fails. 195 | * 196 | * If the original `Future` is successful, the returned `Future` is failed with a `NoSuchElementException`. 197 | * 198 | * $caughtThrowables 199 | * 200 | * @return a failed projection of this `Future`. 201 | * @group Transformations 202 | */ 203 | def failed: Future[Throwable] = 204 | transform({ 205 | t => 206 | if (t.isInstanceOf[Failure[T]]) Success(t.asInstanceOf[Failure[T]].exception) 207 | else Future.failedFailure 208 | })(internalExecutor) 209 | 210 | 211 | /* Monadic operations */ 212 | 213 | /** Asynchronously processes the value in the future once the value becomes available. 214 | * 215 | * WARNING: Will not be called if this future is never completed or if it is completed with a failure. 216 | * 217 | * $swallowsExceptions 218 | * 219 | * @tparam U only used to accept any return type of the given callback function 220 | * @param f the function which will be executed if this `Future` completes with a result, 221 | * the return value of `f` will be discarded. 222 | * @group Callbacks 223 | */ 224 | def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit = onComplete { _ foreach f } 225 | 226 | /** Creates a new future by applying the 's' function to the successful result of 227 | * this future, or the 'f' function to the failed result. If there is any non-fatal 228 | * exception thrown when 's' or 'f' is applied, that exception will be propagated 229 | * to the resulting future. 230 | * 231 | * @tparam S the type of the returned `Future` 232 | * @param s function that transforms a successful result of the receiver into a successful result of the returned future 233 | * @param f function that transforms a failure of the receiver into a failure of the returned future 234 | * @return a `Future` that will be completed with the transformed value 235 | * @group Transformations 236 | */ 237 | def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = 238 | transform { 239 | t => 240 | if (t.isInstanceOf[Success[T]]) t map s 241 | else throw f(t.asInstanceOf[Failure[T]].exception) // will throw fatal errors! 242 | } 243 | 244 | /** Creates a new Future by applying the specified function to the result 245 | * of this Future. If there is any non-fatal exception thrown when 'f' 246 | * is applied then that exception will be propagated to the resulting future. 247 | * 248 | * @tparam S the type of the returned `Future` 249 | * @param f function that transforms the result of this future 250 | * @return a `Future` that will be completed with the transformed value 251 | * @group Transformations 252 | */ 253 | def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S] 254 | 255 | /** Creates a new Future by applying the specified function, which produces a Future, to the result 256 | * of this Future. If there is any non-fatal exception thrown when 'f' 257 | * is applied then that exception will be propagated to the resulting future. 258 | * 259 | * @tparam S the type of the returned `Future` 260 | * @param f function that transforms the result of this future 261 | * @return a `Future` that will be completed with the transformed value 262 | * @group Transformations 263 | */ 264 | def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S] 265 | 266 | 267 | /** Creates a new future by applying a function to the successful result of 268 | * this future. If this future is completed with an exception then the new 269 | * future will also contain this exception. 270 | * 271 | * Example: 272 | * 273 | * {{{ 274 | * val f = Future { "The future" } 275 | * val g = f map { x: String => x + " is now!" } 276 | * }}} 277 | * 278 | * Note that a for comprehension involving a `Future` 279 | * may expand to include a call to `map` and or `flatMap` 280 | * and `withFilter`. See [[scala.concurrent.Future#flatMap]] for an example of such a comprehension. 281 | * 282 | * 283 | * @tparam S the type of the returned `Future` 284 | * @param f the function which will be applied to the successful result of this `Future` 285 | * @return a `Future` which will be completed with the result of the application of the function 286 | * @group Transformations 287 | */ 288 | def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = transform(_ map f) 289 | 290 | /** Creates a new future by applying a function to the successful result of 291 | * this future, and returns the result of the function as the new future. 292 | * If this future is completed with an exception then the new future will 293 | * also contain this exception. 294 | * 295 | * $forComprehensionExamples 296 | * 297 | * @tparam S the type of the returned `Future` 298 | * @param f the function which will be applied to the successful result of this `Future` 299 | * @return a `Future` which will be completed with the result of the application of the function 300 | * @group Transformations 301 | */ 302 | def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = transformWith { 303 | t => 304 | if(t.isInstanceOf[Success[T]]) f(t.asInstanceOf[Success[T]].value) 305 | else this.asInstanceOf[Future[S]] // Safe cast 306 | } 307 | 308 | /** Creates a new future with one level of nesting flattened, this method is equivalent 309 | * to `flatMap(identity)`. 310 | * 311 | * @tparam S the type of the returned `Future` 312 | * @group Transformations 313 | */ 314 | def flatten[S](implicit ev: T <:< Future[S]): Future[S] = flatMap(ev)(internalExecutor) 315 | 316 | /** Creates a new future by filtering the value of the current future with a predicate. 317 | * 318 | * If the current future contains a value which satisfies the predicate, the new future will also hold that value. 319 | * Otherwise, the resulting future will fail with a `NoSuchElementException`. 320 | * 321 | * If the current future fails, then the resulting future also fails. 322 | * 323 | * Example: 324 | * {{{ 325 | * val f = Future { 5 } 326 | * val g = f filter { _ % 2 == 1 } 327 | * val h = f filter { _ % 2 == 0 } 328 | * g foreach println // Eventually prints 5 329 | * Await.result(h, Duration.Zero) // throw a NoSuchElementException 330 | * }}} 331 | * 332 | * @param p the predicate to apply to the successful result of this `Future` 333 | * @return a `Future` which will hold the successful result of this `Future` if it matches the predicate or a `NoSuchElementException` 334 | * @group Transformations 335 | */ 336 | def filter(@deprecatedName('pred) p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = 337 | transform { 338 | t => 339 | if (t.isInstanceOf[Success[T]]) { 340 | if (p(t.asInstanceOf[Success[T]].value)) t 341 | else Future.filterFailure 342 | } else t 343 | } 344 | 345 | /** Used by for-comprehensions. 346 | * @group Transformations 347 | */ 348 | final def withFilter(p: T => Boolean)(implicit executor: ExecutionContext): Future[T] = filter(p)(executor) 349 | 350 | /** Creates a new future by mapping the value of the current future, if the given partial function is defined at that value. 351 | * 352 | * If the current future contains a value for which the partial function is defined, the new future will also hold that value. 353 | * Otherwise, the resulting future will fail with a `NoSuchElementException`. 354 | * 355 | * If the current future fails, then the resulting future also fails. 356 | * 357 | * Example: 358 | * {{{ 359 | * val f = Future { -5 } 360 | * val g = f collect { 361 | * case x if x < 0 => -x 362 | * } 363 | * val h = f collect { 364 | * case x if x > 0 => x * 2 365 | * } 366 | * g foreach println // Eventually prints 5 367 | * Await.result(h, Duration.Zero) // throw a NoSuchElementException 368 | * }}} 369 | * 370 | * @tparam S the type of the returned `Future` 371 | * @param pf the `PartialFunction` to apply to the successful result of this `Future` 372 | * @return a `Future` holding the result of application of the `PartialFunction` or a `NoSuchElementException` 373 | * @group Transformations 374 | */ 375 | def collect[S](pf: PartialFunction[T, S])(implicit executor: ExecutionContext): Future[S] = 376 | transform { 377 | t => 378 | if (t.isInstanceOf[Success[T]]) 379 | Success(pf.applyOrElse(t.asInstanceOf[Success[T]].value, Future.collectFailed)) 380 | else t.asInstanceOf[Failure[S]] 381 | } 382 | 383 | /** Creates a new future that will handle any matching throwable that this 384 | * future might contain. If there is no match, or if this future contains 385 | * a valid result then the new future will contain the same. 386 | * 387 | * Example: 388 | * 389 | * {{{ 390 | * Future (6 / 0) recover { case e: ArithmeticException => 0 } // result: 0 391 | * Future (6 / 0) recover { case e: NotFoundException => 0 } // result: exception 392 | * Future (6 / 2) recover { case e: ArithmeticException => 0 } // result: 3 393 | * }}} 394 | * 395 | * @tparam U the type of the returned `Future` 396 | * @param pf the `PartialFunction` to apply if this `Future` fails 397 | * @return a `Future` with the successful value of this `Future` or the result of the `PartialFunction` 398 | * @group Transformations 399 | */ 400 | def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = 401 | transform { _ recover pf } 402 | 403 | /** Creates a new future that will handle any matching throwable that this 404 | * future might contain by assigning it a value of another future. 405 | * 406 | * If there is no match, or if this future contains 407 | * a valid result then the new future will contain the same result. 408 | * 409 | * Example: 410 | * 411 | * {{{ 412 | * val f = Future { Int.MaxValue } 413 | * Future (6 / 0) recoverWith { case e: ArithmeticException => f } // result: Int.MaxValue 414 | * }}} 415 | * 416 | * @tparam U the type of the returned `Future` 417 | * @param pf the `PartialFunction` to apply if this `Future` fails 418 | * @return a `Future` with the successful value of this `Future` or the outcome of the `Future` returned by the `PartialFunction` 419 | * @group Transformations 420 | */ 421 | def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = 422 | transformWith { 423 | t => 424 | if (t.isInstanceOf[Failure[T]]) { 425 | val result = pf.applyOrElse(t.asInstanceOf[Failure[T]].exception, Future.recoverWithFailed) 426 | if (result ne Future.recoverWithFailedMarker) result 427 | else this 428 | } else this 429 | } 430 | 431 | /** Zips the values of `this` and `that` future, and creates 432 | * a new future holding the tuple of their results. 433 | * 434 | * If `this` future fails, the resulting future is failed 435 | * with the throwable stored in `this`. 436 | * Otherwise, if `that` future fails, the resulting future is failed 437 | * with the throwable stored in `that`. 438 | * 439 | * @tparam U the type of the other `Future` 440 | * @param that the other `Future` 441 | * @return a `Future` with the results of both futures or the failure of the first of them that failed 442 | * @group Transformations 443 | */ 444 | def zip[U](that: Future[U]): Future[(T, U)] = 445 | zipWith(that)(Future.zipWithTuple2)(internalExecutor) 446 | 447 | /** Zips the values of `this` and `that` future using a function `f`, 448 | * and creates a new future holding the result. 449 | * 450 | * If `this` future fails, the resulting future is failed 451 | * with the throwable stored in `this`. 452 | * Otherwise, if `that` future fails, the resulting future is failed 453 | * with the throwable stored in `that`. 454 | * If the application of `f` throws a throwable, the resulting future 455 | * is failed with that throwable if it is non-fatal. 456 | * 457 | * @tparam U the type of the other `Future` 458 | * @tparam R the type of the resulting `Future` 459 | * @param that the other `Future` 460 | * @param f the function to apply to the results of `this` and `that` 461 | * @return a `Future` with the result of the application of `f` to the results of `this` and `that` 462 | * @group Transformations 463 | */ 464 | def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R] = 465 | flatMap(r1 => that.map(r2 => f(r1, r2)))(internalExecutor) 466 | 467 | /** Creates a new future which holds the result of this future if it was completed successfully, or, if not, 468 | * the result of the `that` future if `that` is completed successfully. 469 | * If both futures are failed, the resulting future holds the throwable object of the first future. 470 | * 471 | * Using this method will not cause concurrent programs to become nondeterministic. 472 | * 473 | * Example: 474 | * {{{ 475 | * val f = Future { sys.error("failed") } 476 | * val g = Future { 5 } 477 | * val h = f fallbackTo g 478 | * h foreach println // Eventually prints 5 479 | * }}} 480 | * 481 | * @tparam U the type of the other `Future` and the resulting `Future` 482 | * @param that the `Future` whose result we want to use if this `Future` fails. 483 | * @return a `Future` with the successful result of this or that `Future` or the failure of this `Future` if both fail 484 | * @group Transformations 485 | */ 486 | def fallbackTo[U >: T](that: Future[U]): Future[U] = 487 | if (this eq that) this 488 | else { 489 | implicit val ec = internalExecutor 490 | transformWith { 491 | t => 492 | if (t.isInstanceOf[Success[T]]) this 493 | else that transform { tt => if (tt.isInstanceOf[Success[U]]) tt else t } 494 | } 495 | } 496 | 497 | /** Creates a new `Future[S]` which is completed with this `Future`'s result if 498 | * that conforms to `S`'s erased type or a `ClassCastException` otherwise. 499 | * 500 | * @tparam S the type of the returned `Future` 501 | * @param tag the `ClassTag` which will be used to cast the result of this `Future` 502 | * @return a `Future` holding the casted result of this `Future` or a `ClassCastException` otherwise 503 | * @group Transformations 504 | */ 505 | def mapTo[S](implicit tag: ClassTag[S]): Future[S] = { 506 | implicit val ec = internalExecutor 507 | val boxedClass = { 508 | val c = tag.runtimeClass 509 | if (c.isPrimitive) Future.toBoxed(c) else c 510 | } 511 | require(boxedClass ne null) 512 | map(s => boxedClass.cast(s).asInstanceOf[S]) 513 | } 514 | 515 | /** Applies the side-effecting function to the result of this future, and returns 516 | * a new future with the result of this future. 517 | * 518 | * This method allows one to enforce that the callbacks are executed in a 519 | * specified order. 520 | * 521 | * Note that if one of the chained `andThen` callbacks throws 522 | * an exception, that exception is not propagated to the subsequent `andThen` 523 | * callbacks. Instead, the subsequent `andThen` callbacks are given the original 524 | * value of this future. 525 | * 526 | * The following example prints out `5`: 527 | * 528 | * {{{ 529 | * val f = Future { 5 } 530 | * f andThen { 531 | * case r => sys.error("runtime exception") 532 | * } andThen { 533 | * case Failure(t) => println(t) 534 | * case Success(v) => println(v) 535 | * } 536 | * }}} 537 | * 538 | * $swallowsExceptions 539 | * 540 | * @tparam U only used to accept any return type of the given `PartialFunction` 541 | * @param pf a `PartialFunction` which will be conditionally applied to the outcome of this `Future` 542 | * @return a `Future` which will be completed with the exact same outcome as this `Future` but after the `PartialFunction` has been executed. 543 | * @group Callbacks 544 | */ 545 | def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T] = 546 | transform { 547 | result => 548 | try pf.applyOrElse[Try[T], Any](result, Future.id[Try[T]]) 549 | catch { case t if NonFatal(t) => executor.reportFailure(t) } 550 | 551 | result 552 | } 553 | } 554 | 555 | 556 | 557 | /** Future companion object. 558 | * 559 | * @define nonDeterministic 560 | * Note: using this method yields nondeterministic dataflow programs. 561 | */ 562 | object Future { 563 | 564 | /** 565 | * Utilities, hoisted functions, etc. 566 | */ 567 | 568 | private[future] final val toBoxed = Map[Class[_], Class[_]]( 569 | classOf[Boolean] -> classOf[java.lang.Boolean], 570 | classOf[Byte] -> classOf[java.lang.Byte], 571 | classOf[Char] -> classOf[java.lang.Character], 572 | classOf[Short] -> classOf[java.lang.Short], 573 | classOf[Int] -> classOf[java.lang.Integer], 574 | classOf[Long] -> classOf[java.lang.Long], 575 | classOf[Float] -> classOf[java.lang.Float], 576 | classOf[Double] -> classOf[java.lang.Double], 577 | classOf[Unit] -> classOf[scala.runtime.BoxedUnit] 578 | ) 579 | 580 | private[this] final val _cachedId: AnyRef => AnyRef = Predef.identity _ 581 | 582 | private[future] final def id[T]: T => T = _cachedId.asInstanceOf[T => T] 583 | 584 | private[future] final val collectFailed = 585 | (t: Any) => throw new NoSuchElementException("Future.collect partial function is not defined at: " + t) with NoStackTrace 586 | 587 | private[future] final val filterFailure = 588 | Failure[Nothing](new NoSuchElementException("Future.filter predicate is not satisfied") with NoStackTrace) 589 | 590 | private[future] final val failedFailure = 591 | Failure[Nothing](new NoSuchElementException("Future.failed not completed with a throwable.") with NoStackTrace) 592 | 593 | private[future] final val recoverWithFailedMarker = 594 | scala.future.Future.failed[Nothing](new Throwable with NoStackTrace) 595 | 596 | private[future] final val recoverWithFailed = 597 | (t: Throwable) => recoverWithFailedMarker 598 | 599 | private[future] final def firstCompletedOfException = 600 | new NoSuchElementException("Future.firstCompletedOf empty collection") 601 | 602 | private[this] final val _zipWithTuple2: (Any, Any) => (Any, Any) = Tuple2.apply _ 603 | final def zipWithTuple2[T,U] = _zipWithTuple2.asInstanceOf[(T,U) => (T,U)] 604 | 605 | private[this] final val _addToBuilderFun: (Builder[Any, Nothing], Any) => Builder[Any, Nothing] = (b: Builder[Any, Nothing], e: Any) => b += e 606 | final def addToBuilderFun[A, M[_]] = _addToBuilderFun.asInstanceOf[Function2[Builder[A, M[A]], A, Builder[A, M[A]]]] 607 | 608 | private[future] final val successOfUnit: Success[Unit] = Success(()) 609 | 610 | /** A Future which is never completed. 611 | */ 612 | final object never extends Future[Nothing] { 613 | 614 | @throws(classOf[TimeoutException]) 615 | @throws(classOf[InterruptedException]) 616 | override def ready(atMost: Duration)(implicit permit: CanAwait): this.type = { 617 | atMost match { 618 | case e if e eq Duration.Undefined => throw new IllegalArgumentException("cannot wait for Undefined period") 619 | case Duration.Inf => new CountDownLatch(1).await() 620 | case Duration.MinusInf => // Drop out 621 | case f: FiniteDuration => 622 | if (f > Duration.Zero) new CountDownLatch(1).await(f.toNanos, TimeUnit.NANOSECONDS) 623 | } 624 | throw new TimeoutException(s"Future timed out after [$atMost]") 625 | } 626 | 627 | @throws(classOf[Exception]) 628 | override def result(atMost: Duration)(implicit permit: CanAwait): Nothing = { 629 | ready(atMost) 630 | throw new TimeoutException(s"Future timed out after [$atMost]") 631 | } 632 | 633 | override def onSuccess[U](pf: PartialFunction[Nothing, U])(implicit executor: ExecutionContext): Unit = () 634 | override def onFailure[U](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit = () 635 | override def onComplete[U](f: Try[Nothing] => U)(implicit executor: ExecutionContext): Unit = () 636 | override def isCompleted: Boolean = false 637 | override def value: Option[Try[Nothing]] = None 638 | override def failed: Future[Throwable] = this 639 | override def foreach[U](f: Nothing => U)(implicit executor: ExecutionContext): Unit = () 640 | override def transform[S](s: Nothing => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = this 641 | override def transform[S](f: Try[Nothing] => Try[S])(implicit executor: ExecutionContext): Future[S] = this 642 | override def transformWith[S](f: Try[Nothing] => Future[S])(implicit executor: ExecutionContext): Future[S] = this 643 | override def map[S](f: Nothing => S)(implicit executor: ExecutionContext): Future[S] = this 644 | override def flatMap[S](f: Nothing => Future[S])(implicit executor: ExecutionContext): Future[S] = this 645 | override def flatten[S](implicit ev: Nothing <:< Future[S]): Future[S] = this 646 | override def filter(p: Nothing => Boolean)(implicit executor: ExecutionContext): Future[Nothing] = this 647 | override def collect[S](pf: PartialFunction[Nothing, S])(implicit executor: ExecutionContext): Future[S] = this 648 | override def recover[U >: Nothing](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] = this 649 | override def recoverWith[U >: Nothing](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] = this 650 | override def zip[U](that: Future[U]): Future[(Nothing, U)] = this 651 | override def zipWith[U, R](that: Future[U])(f: (Nothing, U) => R)(implicit executor: ExecutionContext): Future[R] = this 652 | override def fallbackTo[U >: Nothing](that: Future[U]): Future[U] = this 653 | override def mapTo[S](implicit tag: ClassTag[S]): Future[S] = this 654 | override def andThen[U](pf: PartialFunction[Try[Nothing], U])(implicit executor: ExecutionContext): Future[Nothing] = this 655 | 656 | override def toString: String = "Future()" 657 | } 658 | 659 | /** A Future which is completed with the Unit value. 660 | */ 661 | final val unit: Future[Unit] = Promise.fromTry(successOfUnit).future 662 | 663 | /** Creates an already completed Future with the specified exception. 664 | * 665 | * @tparam T the type of the value in the future 666 | * @param exception the non-null instance of `Throwable` 667 | * @return the newly created `Future` instance 668 | */ 669 | def failed[T](exception: Throwable): Future[T] = Promise.failed(exception).future 670 | 671 | /** Creates an already completed Future with the specified result. 672 | * 673 | * @tparam T the type of the value in the future 674 | * @param result the given successful value 675 | * @return the newly created `Future` instance 676 | */ 677 | def successful[T](result: T): Future[T] = Promise.successful(result).future 678 | 679 | /** Creates an already completed Future with the specified result or exception. 680 | * 681 | * @tparam T the type of the value in the `Future` 682 | * @param result the result of the returned `Future` instance 683 | * @return the newly created `Future` instance 684 | */ 685 | def fromTry[T](result: Try[T]): Future[T] = Promise.fromTry(result).future 686 | 687 | /** Starts an asynchronous computation and returns a `Future` instance with the result of that computation. 688 | * 689 | * The following expressions are equivalent: 690 | * 691 | * {{{ 692 | * val f1 = Future(expr) 693 | * val f2 = Future.unit.map(_ => expr) 694 | * val f3 = Future.unit.transform(_ => Success(expr)) 695 | * }}} 696 | * 697 | * The result becomes available once the asynchronous computation is completed. 698 | * 699 | * @tparam T the type of the result 700 | * @param body the asynchronous computation 701 | * @param executor the execution context on which the future is run 702 | * @return the `Future` holding the result of the computation 703 | */ 704 | def apply[T](body: =>T)(implicit @deprecatedName('execctx) executor: ExecutionContext): Future[T] = 705 | unit.transform { _ => Success(body) } 706 | 707 | /** Starts an asynchronous computation and returns a `Future` instance with the result of that computation once it completes. 708 | * 709 | * The following expressions are semantically equivalent: 710 | * 711 | * {{{ 712 | * val f1 = Future(expr).flatten 713 | * val f2 = Future.defer(expr) 714 | * val f3 = Future.unit.flatMap(_ => expr) 715 | * }}} 716 | * 717 | * The result becomes available once the resulting Future of the asynchronous computation is completed. 718 | * 719 | * @tparam T the type of the result 720 | * @param body the asynchronous computation, returning a Future 721 | * @param executor the execution context on which the `body` is evaluated in 722 | * @return the `Future` holding the result of the computation 723 | */ 724 | def defer[T](body: => Future[T])(implicit executor: ExecutionContext): Future[T] = 725 | unit.transformWith { _ => body } 726 | 727 | /** Simple version of `Future.traverse`. Asynchronously and non-blockingly transforms a `TraversableOnce[Future[A]]` 728 | * into a `Future[TraversableOnce[A]]`. Useful for reducing many `Future`s into a single `Future`. 729 | * 730 | * @tparam A the type of the value inside the Futures 731 | * @tparam M the type of the `TraversableOnce` of Futures 732 | * @param in the `TraversableOnce` of Futures which will be sequenced 733 | * @return the `Future` of the `TraversableOnce` of results 734 | */ 735 | def sequence[A, M[X] <: TraversableOnce[X]](in: M[Future[A]])(implicit cbf: CanBuildFrom[M[Future[A]], A, M[A]], executor: ExecutionContext): Future[M[A]] = { 736 | in.foldLeft(successful(cbf(in))) { 737 | (fr, fa) => fr.zipWith(fa)(Future.addToBuilderFun) 738 | }.map(_.result())(InternalCallbackExecutor) 739 | } 740 | 741 | /** Asynchronously and non-blockingly returns a new `Future` to the result of the first future 742 | * in the list that is completed. This means no matter if it is completed as a success or as a failure. 743 | * 744 | * @tparam T the type of the value in the future 745 | * @param futures the `TraversableOnce` of Futures in which to find the first completed 746 | * @return the `Future` holding the result of the future that is first to be completed 747 | */ 748 | def firstCompletedOf[T](futures: TraversableOnce[Future[T]])(implicit executor: ExecutionContext): Future[T] = 749 | if (futures.isEmpty) Future.failed[T](Future.firstCompletedOfException) 750 | else { 751 | val p = Promise[T]() 752 | val firstCompleteHandler = new AtomicReference[Promise[T]](p) with (Try[T] => Unit) { 753 | override def apply(v1: Try[T]): Unit = { 754 | val r = getAndSet(null) 755 | if (r ne null) 756 | r tryComplete v1 757 | } 758 | } 759 | futures foreach { _ onComplete firstCompleteHandler } 760 | p.future 761 | } 762 | 763 | /** Asynchronously and non-blockingly returns a `Future` that will hold the optional result 764 | * of the first `Future` with a result that matches the predicate. 765 | * 766 | * @tparam T the type of the value in the future 767 | * @param futures the `TraversableOnce` of Futures to search 768 | * @param p the predicate which indicates if it's a match 769 | * @return the `Future` holding the optional result of the search 770 | */ 771 | @deprecated("use the overloaded version of this method that takes a scala.collection.immutable.Iterable instead", "2.12.0") 772 | def find[T](@deprecatedName('futurestravonce) futures: TraversableOnce[Future[T]])(@deprecatedName('predicate) p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = { 773 | val futuresBuffer = futures.toBuffer 774 | if (futuresBuffer.isEmpty) successful[Option[T]](None) 775 | else { 776 | val result = Promise[Option[T]]() 777 | val ref = new AtomicInteger(futuresBuffer.size) 778 | val search: Try[T] => Unit = v => try { 779 | if (v.isSuccess && p(v.get)) 780 | result.trySuccess(v.toOption) 781 | } finally { 782 | if (ref.decrementAndGet == 0) 783 | result.trySuccess(None) 784 | } 785 | 786 | futuresBuffer.foreach(_ onComplete search) 787 | 788 | result.future 789 | } 790 | } 791 | 792 | 793 | /** Asynchronously and non-blockingly returns a `Future` that will hold the optional result 794 | * of the first `Future` with a result that matches the predicate, failed `Future`s will be ignored. 795 | * 796 | * @tparam T the type of the value in the future 797 | * @param futures the `scala.collection.immutable.Iterable` of Futures to search 798 | * @param p the predicate which indicates if it's a match 799 | * @return the `Future` holding the optional result of the search 800 | */ 801 | def find[T](futures: scala.collection.immutable.Iterable[Future[T]])(p: T => Boolean)(implicit executor: ExecutionContext): Future[Option[T]] = { 802 | def searchNext(i: Iterator[Future[T]]): Future[Option[T]] = 803 | if (!i.hasNext) successful[Option[T]](None) 804 | else { 805 | i.next().transformWith { 806 | case Success(r) if p(r) => successful(Some(r)) 807 | case other => searchNext(i) 808 | } 809 | } 810 | searchNext(futures.iterator) 811 | } 812 | 813 | /** A non-blocking, asynchronous left fold over the specified futures, 814 | * with the start value of the given zero. 815 | * The fold is performed asynchronously in left-to-right order as the futures become completed. 816 | * The result will be the first failure of any of the futures, or any failure in the actual fold, 817 | * or the result of the fold. 818 | * 819 | * Example: 820 | * {{{ 821 | * val futureSum = Future.foldLeft(futures)(0)(_ + _) 822 | * }}} 823 | * 824 | * @tparam T the type of the value of the input Futures 825 | * @tparam R the type of the value of the returned `Future` 826 | * @param futures the `scala.collection.immutable.Iterable` of Futures to be folded 827 | * @param zero the start value of the fold 828 | * @param op the fold operation to be applied to the zero and futures 829 | * @return the `Future` holding the result of the fold 830 | */ 831 | def foldLeft[T, R](futures: scala.collection.immutable.Iterable[Future[T]])(zero: R)(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = 832 | foldNext(futures.iterator, zero, op) 833 | 834 | private[this] def foldNext[T, R](i: Iterator[Future[T]], prevValue: R, op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = 835 | if (!i.hasNext) successful(prevValue) 836 | else i.next().flatMap { value => foldNext(i, op(prevValue, value), op) } 837 | 838 | /** A non-blocking, asynchronous fold over the specified futures, with the start value of the given zero. 839 | * The fold is performed on the thread where the last future is completed, 840 | * the result will be the first failure of any of the futures, or any failure in the actual fold, 841 | * or the result of the fold. 842 | * 843 | * Example: 844 | * {{{ 845 | * val futureSum = Future.fold(futures)(0)(_ + _) 846 | * }}} 847 | * 848 | * @tparam T the type of the value of the input Futures 849 | * @tparam R the type of the value of the returned `Future` 850 | * @param futures the `TraversableOnce` of Futures to be folded 851 | * @param zero the start value of the fold 852 | * @param op the fold operation to be applied to the zero and futures 853 | * @return the `Future` holding the result of the fold 854 | */ 855 | @deprecated("use Future.foldLeft instead", "2.12.0") 856 | def fold[T, R](futures: TraversableOnce[Future[T]])(zero: R)(@deprecatedName('foldFun) op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = { 857 | if (futures.isEmpty) successful(zero) 858 | else sequence(futures).map(_.foldLeft(zero)(op)) 859 | } 860 | 861 | /** Initiates a non-blocking, asynchronous, fold over the supplied futures 862 | * where the fold-zero is the result value of the `Future` that's completed first. 863 | * 864 | * Example: 865 | * {{{ 866 | * val futureSum = Future.reduce(futures)(_ + _) 867 | * }}} 868 | * @tparam T the type of the value of the input Futures 869 | * @tparam R the type of the value of the returned `Future` 870 | * @param futures the `TraversableOnce` of Futures to be reduced 871 | * @param op the reduce operation which is applied to the results of the futures 872 | * @return the `Future` holding the result of the reduce 873 | */ 874 | @deprecated("use Future.reduceLeft instead", "2.12.0") 875 | def reduce[T, R >: T](futures: TraversableOnce[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = { 876 | if (futures.isEmpty) failed(new NoSuchElementException("reduce attempted on empty collection")) 877 | else sequence(futures).map(_ reduceLeft op) 878 | } 879 | 880 | /** Initiates a non-blocking, asynchronous, left reduction over the supplied futures 881 | * where the zero is the result value of the first `Future`. 882 | * 883 | * Example: 884 | * {{{ 885 | * val futureSum = Future.reduceLeft(futures)(_ + _) 886 | * }}} 887 | * @tparam T the type of the value of the input Futures 888 | * @tparam R the type of the value of the returned `Future` 889 | * @param futures the `scala.collection.immutable.Iterable` of Futures to be reduced 890 | * @param op the reduce operation which is applied to the results of the futures 891 | * @return the `Future` holding the result of the reduce 892 | */ 893 | def reduceLeft[T, R >: T](futures: scala.collection.immutable.Iterable[Future[T]])(op: (R, T) => R)(implicit executor: ExecutionContext): Future[R] = { 894 | val i = futures.iterator 895 | if (!i.hasNext) failed(new NoSuchElementException("reduceLeft attempted on empty collection")) 896 | else i.next() flatMap { v => foldNext(i, v, op) } 897 | } 898 | 899 | /** Asynchronously and non-blockingly transforms a `TraversableOnce[A]` into a `Future[TraversableOnce[B]]` 900 | * using the provided function `A => Future[B]`. 901 | * This is useful for performing a parallel map. For example, to apply a function to all items of a list 902 | * in parallel: 903 | * 904 | * {{{ 905 | * val myFutureList = Future.traverse(myList)(x => Future(myFunc(x))) 906 | * }}} 907 | * @tparam A the type of the value inside the Futures in the `TraversableOnce` 908 | * @tparam B the type of the value of the returned `Future` 909 | * @tparam M the type of the `TraversableOnce` of Futures 910 | * @param in the `TraversableOnce` of Futures which will be sequenced 911 | * @param fn the function to apply to the `TraversableOnce` of Futures to produce the results 912 | * @return the `Future` of the `TraversableOnce` of results 913 | */ 914 | def traverse[A, B, M[X] <: TraversableOnce[X]](in: M[A])(fn: A => Future[B])(implicit cbf: CanBuildFrom[M[A], B, M[B]], executor: ExecutionContext): Future[M[B]] = 915 | in.foldLeft(successful(cbf(in))) { 916 | (fr, a) => fr.zipWith(fn(a))(Future.addToBuilderFun) 917 | }.map(_.result())(InternalCallbackExecutor) 918 | 919 | 920 | // This is used to run callbacks which are internal 921 | // to scala.concurrent; our own callbacks are only 922 | // ever used to eventually run another callback, 923 | // and that other callback will have its own 924 | // executor because all callbacks come with 925 | // an executor. Our own callbacks never block 926 | // and have no "expected" exceptions. 927 | // As a result, this executor can do nothing; 928 | // some other executor will always come after 929 | // it (and sometimes one will be before it), 930 | // and those will be performing the "real" 931 | // dispatch to code outside scala.concurrent. 932 | // Because this exists, ExecutionContext.defaultExecutionContext 933 | // isn't instantiated by Future internals, so 934 | // if some code for some reason wants to avoid 935 | // ever starting up the default context, it can do so 936 | // by just not ever using it itself. scala.concurrent 937 | // doesn't need to create defaultExecutionContext as 938 | // a side effect. 939 | private[future] final object InternalCallbackExecutor extends ExecutionContext with java.util.concurrent.Executor with BatchingExecutor { 940 | override protected def unbatchedExecute(r: Runnable): Unit = r.run() 941 | override def reportFailure(t: Throwable): Unit = ExecutionContext.defaultReporter(t) 942 | } 943 | } 944 | 945 | /** A marker indicating that a `java.lang.Runnable` provided to `scala.concurrent.ExecutionContext` 946 | * wraps a callback provided to `Future.onComplete`. 947 | * All callbacks provided to a `Future` end up going through `onComplete`, so this allows an 948 | * `ExecutionContext` to special-case callbacks that were executed by `Future` if desired. 949 | */ 950 | trait OnCompleteRunnable { 951 | self: Runnable => 952 | } 953 | 954 | --------------------------------------------------------------------------------