Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在scala上,如何等待未来。onFailure完成?_Scala - Fatal编程技术网

在scala上,如何等待未来。onFailure完成?

在scala上,如何等待未来。onFailure完成?,scala,Scala,Scala期货: 使用wait.result,我可以在终止程序之前等待将来完成 如何在终止程序之前等待Future.on失败完成 package test import scala.concurrent.duration.Duration import scala.concurrent.{Await, Future} import scala.concurrent.ExecutionContext.Implicits.global object Test5 extends App { d

Scala期货: 使用wait.result,我可以在终止程序之前等待将来完成

如何在终止程序之前等待Future.on失败完成

package test

import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global

object Test5 extends App {
  def step(i: Int): Future[String] = Future {
    Thread.sleep(1000)
    if (i == 3) throw new Exception("exception on t3")
    Thread.sleep(1000); val s = s"done: $i"; println(s); s
  }

  val task: Future[String] = step(1).flatMap(_ => step(2).flatMap(_ => step(3)))

  task.onFailure {
    case e: Throwable => println("task.onFailure. START: " + e); Thread.sleep(3000); println("task.onFailure. END.")
  }

  try {
    val result: String = Await.result(task, Duration.Inf)
    println("RESULT: " + result)
  } catch {
    case e: Throwable => println("Await.result.try catch: " + e)
  }

  // without this, "task.onFailure. END." does not get printed.
  // How can I replace this line with something such as Await.result([the task.onFailure I set previously])
  Thread.sleep(5000)  

  println("END")
}
注意:我没有使用
task.onFailure
,而是可以捕获
wait.result
上的异常(如示例所示)。但是我更喜欢使用
task.onFailure


更新
解决方案是按照Ryan的建议使用
转换
恢复
。在我的例子中,我需要更多的东西,我添加了这个替代答案:

onFailure
返回
Unit
。这是无法阻止的

wait.result
上捕获异常,或者使用
transform
recover
对异常产生副作用。

您不能
Future#onFailure
返回
Unit
,因此没有可用于阻止执行的句柄


由于您正在阻止
任务的完成
,因此代码中的
catch
子句相当于从
onFailure
中获得的内容。也就是说,如果
Future
失败,那么
catch
的主体将在程序退出之前执行,因为它正在主线程上运行(而
onComplete
不是)。

我们可以通过
onComplete2
onComplete2
来丰富
Future
,如下所示:

import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.util.Try

object FutureUtils {
  implicit class RichFuture[T](val self: Future[T]) {
    def onComplete2[U](f: (Try[T]) => U)(implicit executor: ExecutionContext): Future[T] = {
      val p = Promise[T]()
      self.onComplete { r: Try[T] => f(r); p.complete(r) }
      p.future
    }

    def onCompleteWith2[U](f: (Try[T]) => Future[U])(implicit executor: ExecutionContext): Future[T] = {
      val p = Promise[T]()
      self.onComplete { r: Try[T] => f(r).onComplete(_ => p.complete(r)) }
      p.future
    }    
  }
}
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import FutureUtils._

import scala.util.{Failure, Success, Try}

object Test5 extends App {
  def stepf(i: Int): Future[String] = Future { step(i) }

  def step(i: Int): String = {
    Thread.sleep(1000)
    if (i == 3) throw new Exception("exception on t3")
    Thread.sleep(1000); val s = s"done: $i"; println(s); s
  }

  val task1: Future[String] =
    stepf(1).flatMap(_ => stepf(2).flatMap(_ => stepf(3)))

  // the result of step(10) and step(11) is ignored
  val task2: Future[String] = task1.onComplete2((r: Try[String]) => r match {
    case Success(s) => step(10)
    case Failure(e) => step(11)
  })

/*
  // If I want to recover (and so, to avoid an exception on Await.result:
  val task3 = task2.recover {case e: Throwable => step(12) }


  // I can use onCompleteWith2 instead of onComplete2
  val task2: Future[String] = task1.onCompleteWith2((r: Try[String]) => r match {
    case Success(s) => stepf(10)
    case Failure(e) => stepf(11)
  })
*/

  try {
    val result = Await.result(task2, Duration.Inf)
    println("RESULT: " + result)
  } catch {
    // see my comment above to remove this
    case e: Throwable => println("Await.result.try catch: " + e)
  }

  println("END.")
}
done: 1
done: 2
done: 11
Await.result.try catch: java.lang.Exception: exception on t3
END.
然后我按如下方式使用它:

import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.util.Try

object FutureUtils {
  implicit class RichFuture[T](val self: Future[T]) {
    def onComplete2[U](f: (Try[T]) => U)(implicit executor: ExecutionContext): Future[T] = {
      val p = Promise[T]()
      self.onComplete { r: Try[T] => f(r); p.complete(r) }
      p.future
    }

    def onCompleteWith2[U](f: (Try[T]) => Future[U])(implicit executor: ExecutionContext): Future[T] = {
      val p = Promise[T]()
      self.onComplete { r: Try[T] => f(r).onComplete(_ => p.complete(r)) }
      p.future
    }    
  }
}
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import FutureUtils._

import scala.util.{Failure, Success, Try}

object Test5 extends App {
  def stepf(i: Int): Future[String] = Future { step(i) }

  def step(i: Int): String = {
    Thread.sleep(1000)
    if (i == 3) throw new Exception("exception on t3")
    Thread.sleep(1000); val s = s"done: $i"; println(s); s
  }

  val task1: Future[String] =
    stepf(1).flatMap(_ => stepf(2).flatMap(_ => stepf(3)))

  // the result of step(10) and step(11) is ignored
  val task2: Future[String] = task1.onComplete2((r: Try[String]) => r match {
    case Success(s) => step(10)
    case Failure(e) => step(11)
  })

/*
  // If I want to recover (and so, to avoid an exception on Await.result:
  val task3 = task2.recover {case e: Throwable => step(12) }


  // I can use onCompleteWith2 instead of onComplete2
  val task2: Future[String] = task1.onCompleteWith2((r: Try[String]) => r match {
    case Success(s) => stepf(10)
    case Failure(e) => stepf(11)
  })
*/

  try {
    val result = Await.result(task2, Duration.Inf)
    println("RESULT: " + result)
  } catch {
    // see my comment above to remove this
    case e: Throwable => println("Await.result.try catch: " + e)
  }

  println("END.")
}
done: 1
done: 2
done: 11
Await.result.try catch: java.lang.Exception: exception on t3
END.
执行情况如下:

import scala.concurrent.{ExecutionContext, Future, Promise}
import scala.util.Try

object FutureUtils {
  implicit class RichFuture[T](val self: Future[T]) {
    def onComplete2[U](f: (Try[T]) => U)(implicit executor: ExecutionContext): Future[T] = {
      val p = Promise[T]()
      self.onComplete { r: Try[T] => f(r); p.complete(r) }
      p.future
    }

    def onCompleteWith2[U](f: (Try[T]) => Future[U])(implicit executor: ExecutionContext): Future[T] = {
      val p = Promise[T]()
      self.onComplete { r: Try[T] => f(r).onComplete(_ => p.complete(r)) }
      p.future
    }    
  }
}
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import FutureUtils._

import scala.util.{Failure, Success, Try}

object Test5 extends App {
  def stepf(i: Int): Future[String] = Future { step(i) }

  def step(i: Int): String = {
    Thread.sleep(1000)
    if (i == 3) throw new Exception("exception on t3")
    Thread.sleep(1000); val s = s"done: $i"; println(s); s
  }

  val task1: Future[String] =
    stepf(1).flatMap(_ => stepf(2).flatMap(_ => stepf(3)))

  // the result of step(10) and step(11) is ignored
  val task2: Future[String] = task1.onComplete2((r: Try[String]) => r match {
    case Success(s) => step(10)
    case Failure(e) => step(11)
  })

/*
  // If I want to recover (and so, to avoid an exception on Await.result:
  val task3 = task2.recover {case e: Throwable => step(12) }


  // I can use onCompleteWith2 instead of onComplete2
  val task2: Future[String] = task1.onCompleteWith2((r: Try[String]) => r match {
    case Success(s) => stepf(10)
    case Failure(e) => stepf(11)
  })
*/

  try {
    val result = Await.result(task2, Duration.Inf)
    println("RESULT: " + result)
  } catch {
    // see my comment above to remove this
    case e: Throwable => println("Await.result.try catch: " + e)
  }

  println("END.")
}
done: 1
done: 2
done: 11
Await.result.try catch: java.lang.Exception: exception on t3
END.
如果我们没有在
步骤(3)
中抛出异常,则执行如下。请注意,结果是“完成:3”,而不是“完成:10”:


如果您只想对副作用进行排序,这样您就知道副作用已经执行了,我建议使用“and then”。

onFailure
在future异常失败时被调用。您可以在失败的未来等待
onFailure
获得called@pamu仅仅等待最初的未来是不够的。
onFailure
回调是异步安排的,这意味着它可以在最初的未来完成后的任意时间内发生。谢谢,
transform
recover
帮助我理解了如何构建这个替代方案:正如Viktor所说,
future。然后
就足够了。它与complete2上的
类似(使用
PartialFunction
onCompleteWith2
对于链接
未来可能仍然有用。