假设我的未来定义如下所示:
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) )
这个未来的执行时间是5秒(5 * 5 * 200ms)。
我正在寻找一种将这种未来封装在某种“超时上下文”中并通过超时停止执行的方式,因此并非所有转换都将被执行。
理想情况下,我设想有这样的东西:
Future("Hello ")
.within(2 seconds)
.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 ...
答案 0 :(得分:1)
以下是几种方法:
0)不要链接Future
。执行是顺序执行的,因此只需在单个Future
中使用一个循环并跟踪循环中的总经过时间即可。
1)在val
之外的Future
中记录开始时间,并使用此时间来修改为appendCharWithTimeout
设置的超时值,以使总执行时间不会超过。
2)让appendCharWithTimeout
占用总执行时间,并将剩余时间返回到下一次迭代。超过超时时间时,使用此命令停止执行。
选择取决于实际代码的实际作用以及是否可以在appendCharWithTimeout
中更改代码。
答案 1 :(得分:-1)
首先,请不要将Thread.sleep
与期货混在一起。期货与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}")
})