如何通过超时取消链接的Scala future?

如何通过超时取消链接的Scala future?,scala,functional-programming,timeout,concurrent.futures,Scala,Functional Programming,Timeout,Concurrent.futures,假设我的未来定义如下: import scala.concurrent.Future def appendCharWithTimeout(transformationId: String, char: Char, delayTimeMs: Long, delayTimes: Int) = (s: String) => { for (i <- 1 to delayTimes) { println(s"$transformationId waiting iteration

假设我的未来定义如下:

import scala.concurrent.Future

def appendCharWithTimeout(transformationId: String, char: Char, delayTimeMs: Long, delayTimes: Int) = (s: String) => {
  for (i <- 1 to delayTimes) {
    println(s"$transformationId waiting iteration $i ...")
    Thread.sleep(delayTimeMs)
  }
  s"$s$char"
}

Future("Hello ")
  .map( appendCharWithTimeout("mapJ", 'J', 200, 5) )
  .map( appendCharWithTimeout("mapO", 'o', 200, 5) )
  .map( appendCharWithTimeout("mapH", 'h', 200, 5) )
  .map( appendCharWithTimeout("mapN", 'n', 200, 5) )
  .map( appendCharWithTimeout("map!", '!', 200, 5) )
输出应为:

mapJ waiting iteration 1 ...
mapJ waiting iteration 2 ...
mapJ waiting iteration 3 ...
mapJ waiting iteration 4 ...
mapJ waiting iteration 5 ...
mapO waiting iteration 1 ...
mapO waiting iteration 2 ...
mapO waiting iteration 3 ...
mapO waiting iteration 4 ...
mapO waiting iteration 5 ...

首先,请不要将
线程、睡眠
与未来混为一谈。Futures使用ExecutionContext来调度线程池上的计算。所以,如果你的未来将阻止上述线程。。。这将导致问题

import java.util.{Timer, TimerTask}

import scala.concurrent.{Future, Promise}
import scala.concurrent.duration.{Duration, TimeUnit}
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}


def createFutureWithDelay[T](result: T, timeout: Duration) = {
  val promise = Promise[T]
  val timerTask = new TimerTask {
    override def run(): Unit = promise.success(result)
  }
  val timer = new Timer()
  timer.schedule(timerTask, timeout.toMillis)
  promise.future
}

def getNonBlockingFutureWithTimeout[A, T](computation: => T, timeout: Duration, t: Throwable) = {
  val promise = Promise[T]
  promise.tryCompleteWith(Future(computation))
  val timerTask = new TimerTask {
    override def run(): Unit = promise.failure(t)
  }
  val timer = new Timer()
  timer.schedule(timerTask, timeout.toMillis)
  promise.future
}

def wrapFutureWithTimeout[T](f: Future[T], timeout: Duration, t: Throwable) = {
  val promise = Promise[T]
  promise.tryCompleteWith(f)
  val timerTask = new TimerTask {
    override def run(): Unit = promise.failure(t)
  }
  val timer = new Timer()
  timer.schedule(timerTask, timeout.toMillis)
  promise.future
}

val f = createFutureWithDelay(5, 5 minutes).flatMap(_ => createFutureWithDelay(5, 5 minutes))

val f2 = wrapFutureWithTimeout(f, 5 seconds, new Throwable("ENDING with timeout"))

f2.onComplete({
  case Success(value) => println(s"success - $value")
  case Failure(t) => println(s"failure - ${t.getMessage}")
})

以下是几种方法:

0)不要将
Future
s链接起来。执行是顺序的,因此只需在单个
未来
中使用一个循环,并跟踪循环中经过的总时间

1) 在
val
中记录
Future
之外的开始时间,并使用它修改给定给
appendCharWithTimeout
的超时值,以便不超过总执行时间

2) 让
appendCharWithTimeout
获取总执行时间,并将剩余时间返回到下一次迭代。使用此选项可在超过超时时停止执行


选择取决于实际代码的实际功能,以及您是否可以在
appendCharWithTimeout

中更改代码。即使
最终未来
是通过顺序执行
链接期货
来计算的,但这可能是另一个问题,所花费的时间仍然被计算为
最终未来
的中断时间,您可以使用
等待
以阻塞方式或使用
定时器
承诺
以非阻塞方式对
最终未来
执行超时。所有提到的选项都依赖于显式的时间执行跟踪。我正在寻找一种隐含的方法来实现这一点。在Twitter Futures中找到了我所需要的东西-。。。
import java.util.{Timer, TimerTask}

import scala.concurrent.{Future, Promise}
import scala.concurrent.duration.{Duration, TimeUnit}
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.util.{Failure, Success}


def createFutureWithDelay[T](result: T, timeout: Duration) = {
  val promise = Promise[T]
  val timerTask = new TimerTask {
    override def run(): Unit = promise.success(result)
  }
  val timer = new Timer()
  timer.schedule(timerTask, timeout.toMillis)
  promise.future
}

def getNonBlockingFutureWithTimeout[A, T](computation: => T, timeout: Duration, t: Throwable) = {
  val promise = Promise[T]
  promise.tryCompleteWith(Future(computation))
  val timerTask = new TimerTask {
    override def run(): Unit = promise.failure(t)
  }
  val timer = new Timer()
  timer.schedule(timerTask, timeout.toMillis)
  promise.future
}

def wrapFutureWithTimeout[T](f: Future[T], timeout: Duration, t: Throwable) = {
  val promise = Promise[T]
  promise.tryCompleteWith(f)
  val timerTask = new TimerTask {
    override def run(): Unit = promise.failure(t)
  }
  val timer = new Timer()
  timer.schedule(timerTask, timeout.toMillis)
  promise.future
}

val f = createFutureWithDelay(5, 5 minutes).flatMap(_ => createFutureWithDelay(5, 5 minutes))

val f2 = wrapFutureWithTimeout(f, 5 seconds, new Throwable("ENDING with timeout"))

f2.onComplete({
  case Success(value) => println(s"success - $value")
  case Failure(t) => println(s"failure - ${t.getMessage}")
})