将来在Scala中包装阻塞Try[T]的最佳方法是什么?
问题是,我有一个库,它有一个阻塞方法返回Try[T]。但是因为它是阻塞的,所以我想使用Future[T]使它成为非阻塞的。在以后的块中,我还想计算一些依赖于originblocking方法返回值的内容 但是如果我使用下面这样的东西,那么我的将来在Scala中包装阻塞Try[T]的最佳方法是什么?,scala,Scala,问题是,我有一个库,它有一个阻塞方法返回Try[T]。但是因为它是阻塞的,所以我想使用Future[T]使它成为非阻塞的。在以后的块中,我还想计算一些依赖于originblocking方法返回值的内容 但是如果我使用下面这样的东西,那么我的非阻塞将返回Future[Try[T]],因为Future[T]可能已经表示失败[U],所以我更愿意将异常传播到Future[T]is self def blockMethod(x: Int): Try[Int] = Try { // Some long
非阻塞
将返回Future[Try[T]],因为Future[T]可能已经表示失败[U],所以我更愿意将异常传播到Future[T]is self
def blockMethod(x: Int): Try[Int] = Try {
// Some long operation to get an Int from network or IO
throw new Exception("Network Exception") }
}
def nonBlocking(x: Int): Future[Try[Int]] = future {
blockMethod(x).map(_ * 2)
}
下面是我尝试过的,我只是在future{}
块中使用.get
方法,但我不确定这是否是最好的方法
def blockMethod(x: Int): Try[Int] = Try {
// Some long operation to get an Int from network or IO
throw new Exception("Network Exception") }
}
def nonBlocking(x: Int): Future[Int] = future {
blockMethod(x).get * 2
}
这样做正确吗?或者有一种更为scala惯用的方式将t Try[t]转换为未来的[t]?这里有一个不会阻塞的示例,请注意,您可能希望使用自己的执行上下文,而不是scala的全局上下文:
import scala.util._
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global
object Main extends App {
def blockMethod(x: Int): Try[Int] = Try {
// Some long operation to get an Int from network or IO
Thread.sleep(10000)
100
}
def tryToFuture[A](t: => Try[A]): Future[A] = {
future {
t
}.flatMap {
case Success(s) => Future.successful(s)
case Failure(fail) => Future.failed(fail)
}
}
// Initiate long operation
val f = tryToFuture(blockMethod(1))
println("Waiting... 10 seconds to complete")
// Should return before 20 seconds...
val res = Await.result(f, 20 seconds)
println(res) // prints 100
}
我认为:Try&Future是一个一元结构,惯用的方式是一元构图(用于理解): 您需要为将来定义monad transformer[Try[\u]](库的代码): 和使用示例:
def blockMethod(x: Int): Try[Int] = Try {
Thread.sleep(5000)
if(x < 10) throw new IllegalArgumentException
else x + 1
}
import FutureT._
// idiomatic way :)
val async = for {
x <- futureTry { blockMethod(15) }
y <- futureTry { blockMethod(25) }
} yield (x + y) * 2 // possible due to using modan transformer
println("Waiting... 10 seconds to complete")
val res = Await.result(async, 20 seconds)
println(res)
// example with Exception
val asyncWithError = for {
x <- futureTry { blockMethod(5) }
y <- futureTry { blockMethod(25) }
} yield (x + y) * 2 // possible due to using modan transformer
// Can't use Await because will get exception
// when extract value from FutureT(Failure(java.lang.IllegalArgumentException))
// no difference between Failure produced by Future or Try
asyncWithError onComplete {
case Failure(e) => println(s"Got exception: $e.msg")
case Success(res) => println(res)
}
// Output:
// Got exception: java.lang.IllegalArgumentException.msg
def blockMethod(x:Int):Try[Int]=Try{
线程。睡眠(5000)
如果(x<10)抛出新的IllegalArgumentException
其他x+1
}
进口期货
//惯用方式:)
val async=for{
如果你知道你正在阻塞,你不是应该把代码包装在阻塞中吗fromTry
方法对此有用吗?自我更正我之前的评论:fromTry
实际上阻塞了,所以没有运气。我已经运行了更多的实验,实际上未来(t.get)
似乎也不会阻塞线程。它看起来比flatMapping更简单。想法?有一个bug。通过blockMethod(5)
更改blockMethod(15)
会导致异常终止程序,最后一行println(res)
未执行。谢谢David,我错过了异常行为的描述,请使用异常示例更新我的答案。
def blockMethod(x: Int): Try[Int] = Try {
Thread.sleep(5000)
if(x < 10) throw new IllegalArgumentException
else x + 1
}
import FutureT._
// idiomatic way :)
val async = for {
x <- futureTry { blockMethod(15) }
y <- futureTry { blockMethod(25) }
} yield (x + y) * 2 // possible due to using modan transformer
println("Waiting... 10 seconds to complete")
val res = Await.result(async, 20 seconds)
println(res)
// example with Exception
val asyncWithError = for {
x <- futureTry { blockMethod(5) }
y <- futureTry { blockMethod(25) }
} yield (x + y) * 2 // possible due to using modan transformer
// Can't use Await because will get exception
// when extract value from FutureT(Failure(java.lang.IllegalArgumentException))
// no difference between Failure produced by Future or Try
asyncWithError onComplete {
case Failure(e) => println(s"Got exception: $e.msg")
case Success(res) => println(res)
}
// Output:
// Got exception: java.lang.IllegalArgumentException.msg