将阻塞代码转换为使用scala期货
我的旧代码如下所示,其中所有db调用都被阻塞 我需要帮助将此转换为使用期货将阻塞代码转换为使用scala期货,scala,asynchronous,Scala,Asynchronous,我的旧代码如下所示,其中所有db调用都被阻塞 我需要帮助将此转换为使用期货 def getUserPoints(username: String): Option[Long] db.getUserPoints(username) match { case Some(userPoints) => Some(userPoints.total) case None => { if (db.getSomething("abc")
def getUserPoints(username: String): Option[Long]
db.getUserPoints(username) match {
case Some(userPoints) => Some(userPoints.total)
case None => {
if (db.getSomething("abc").isEmpty) {
db.somethingElse("asdf") match {
case Some(pointId) => {
db.setPoints(pointId, username)
db.findPointsForUser(username)
}
case _ => None
}
} else {
db.findPointsForUser(username)
}
}
}
}
db.getUserPoints(username: String): Future[Option[UserPoints]]
db.getSomething(s: String): Future[Option[Long]]
db.setPoints(pointId, username): Future[Unit]
db.findPointsForUser(username): Future[Option[Long]]
我的新API低于我返回的期货
def getUserPoints(username: String): Option[Long]
db.getUserPoints(username) match {
case Some(userPoints) => Some(userPoints.total)
case None => {
if (db.getSomething("abc").isEmpty) {
db.somethingElse("asdf") match {
case Some(pointId) => {
db.setPoints(pointId, username)
db.findPointsForUser(username)
}
case _ => None
}
} else {
db.findPointsForUser(username)
}
}
}
}
db.getUserPoints(username: String): Future[Option[UserPoints]]
db.getSomething(s: String): Future[Option[Long]]
db.setPoints(pointId, username): Future[Unit]
db.findPointsForUser(username): Future[Option[Long]]
我如何将上述内容转换为使用我的新API(使用futures)
我尝试使用for compr,但开始出现wierd错误,比如Future[什么都没有]
var userPointsFut: Future[Long] = for {
userPointsOpt <- db.getUserPoints(username)
userPoints <- userPointsOpt
} yield userPoints.total
var userpoints out:Future[Long]=for{
userPointsOpt我认为这种设计的第一个问题是,对未来的
阻塞调用的端口不应包装选项类型:
阻塞调用:
def-methingblocking(for:Id):选项[T]
应成为:
def-methingblocking(for:Id):未来[T]
而不是:
def-methingblocking(for:Id):未来[选项[T]]
阻塞调用给出一个值Some(value)
或None
,非阻塞未来版本给出一个Success(value)
或Failure(exception)
,以非阻塞方式完全保留选项的语义
考虑到这一点,我们可以在Future
上使用组合器对相关流程进行建模。让我们看看如何:
首先,让我们将API重构为我们可以使用的东西:
type UserPoints = Long
object db {
def getUserPoints(username: String): Future[UserPoints] = ???
def getSomething(s: String): Future[UserPoints] = ???
def setPoints(pointId:UserPoints, username: String): Future[Unit] = ???
def findPointsForUser(username: String): Future[UserPoints] = ???
}
class PointsNotFound extends Exception("bonk")
class StuffNotFound extends Exception("sthing not found")
然后,该过程将如下所示:
def getUserPoints(username:String): Future[UserPoints] = {
db.getUserPoints(username)
.map(userPoints => userPoints /*.total*/)
.recoverWith{
case ex:PointsNotFound =>
(for {
sthingElse <- db.getSomething("abc")
_ <- db.setPoints(sthingElse, username)
points <- db.findPointsForUser(username)
} yield (points))
.recoverWith{
case ex: StuffNotFound => db.findPointsForUser(username)
}
}
}
现在我们可以重新编写我们的流程,保持与基于未来的合成相同的结构
type UserPoints = Long
object db {
def getUserPoints(username: String): Future[Option[UserPoints]] = ???
def getSomething(s: String): Future[Option[Long]] = ???
def setPoints(pointId: UserPoints, username:String): Future[Unit] = ???
def findPointsForUser(username: String): Future[Option[Long]] = ???
}
class PointsNotFound extends Exception("bonk")
class StuffNotFound extends Exception("sthing not found")
def getUserPoints2(username:String): Future[Option[UserPoints]] = {
val futureOpt = FutureO(db.getUserPoints(username))
.map(userPoints => userPoints /*.total*/)
.orElse{
(for {
sthingElse <- FutureO(db.getSomething("abc"))
_ <- FutureO(db.setPoints(sthingElse, username).map(_ => Some(())))
points <- FutureO(db.findPointsForUser(username))
} yield (points))
.orElse{
FutureO(db.findPointsForUser(username))
}
}
futureOpt.future
}
type UserPoints=Long
对象数据库{
def getUserPoints(用户名:字符串):未来[选项[UserPoints]]=???
def getSomething(s:String):Future[Option[Long]]=???
def设定点(pointId:UserPoints,username:String):未来[单位]=???
def findPointsForUser(用户名:字符串):未来[选项[长]]=???
}
类pointsnotfind扩展异常(“bonk”)
类StuffNotFound扩展异常(“未找到sthing”)
def getUserPoints2(用户名:字符串):未来[选项[UserPoints]]={
val futureOpt=FutureO(db.getUserPoints(用户名))
.map(userPoints=>userPoints/*.total*/)
orElse{
(用于{
sthingElse我不能真正更改Future[Option[UserPoints]],我的库返回Future选项。@coolbreeze我添加了一种方法,在Future[Option[t]]
上保留了相同的合成结构。我意识到我以前的回答中存在一个缺陷。如果您希望在返回值为Future(None)时恢复
我们需要另一个combinatororElse
,我已经介绍了它。相应地更新了其余的答案。你不应该在你的问题中发布答案。将其发布为“答案”。@talex我无法理解你评论的原因。想解释一下吗?