将我的阻塞播放/scala/slick 算法更改为不阻塞
Changing my blocking play / scala /slick algorithm not to block
这是一个相对简单的问题,我确信我遗漏了一些基本的东西。
- 我正在使用 Slick 查询数据库。
- 我知道它会返回一个序列,该序列将包含缺失值...
- 所以我想将它们添加到......但我事先不知道这些值。
然后最终生成一个 csv 文件供其他人使用...
def annualAtomTesting(peril: String , region: String) = Action {
val theResult: Future[Seq[SingleEventYear]] = db.run(filterAnnualPerilAndRegionFillGaps(peril, region).result)
val years = theResult.map { list => list.map(s => s.year).toSet}
val allYear = (1 to 10000) toSet
val dbYears = Await.result( years , Duration.Inf )
val theDifference = allYear.diff( dbYears )
val whatsMissing = theDifference.map(s => new SingleEventYear(region, peril, 0 ,0 , s, 0))
val intermediate: String = Await.result( theResult.map(result => header + result.mkString("\n") + "\n"
+ whatsMissing.mkString("\r\n") ), Duration.Inf )
Ok(intermediate)
}
因此,从 1,2,3,4,5 的潜在系列中,我可能会从数据库查询中得到 2、4、5。此代码添加了 1 和 3...但我的理解是它会阻止所有内容,这有点顽皮。
对于我所尝试的一切,我无法在未来找到如何让 .diff 方法(这看起来是最干净的策略)在 'Future'、非阻塞上下文中运行。
我是不是漏掉了什么?
这里你只有一个 Future,你不需要创建多个 Await.result。
您可以通过切换到 Action.async:
来摆脱所有 Await.result(...) 电话
Action.async {
val allYear = (1 to 10000).toSet
val intermediate:Future[String] = for (
res <- db.run(filterAnnualPerilAndRegionFillGaps(peril, region).result)
) yield (
header + res.mkString("\n") + "\n" +
allYear.diff(res.map (s => s.year).toSet).map(s => new SingleEventYear(region, peril, 0 ,0 , s, 0)).mkString("\r\n")
)
intermediate.map(item => Ok(item))
}
这是如何执行此操作的另一个示例:
def annualAtomTesting(peril: String, region: String) = Action.async {
for {
results <- db.run(filterAnnualPerilAndRegionFillGaps(peril, region).result)
years = results.map(_.year).toSet
allYears = (1 to 10000).toSet
differences = allYears diff years
missing = differences.map(new SingleEventYear(region, peril, 0, 0, _, 0))
intermediate = header + results.mkString("\n") + "\n" + missing.mkString("\r\n")
} yield Ok(intermediate)
}
您不应在生产代码中使用 Await
。 Play 允许您使用需要 return Future[Result]
而不是 Result
.
的异步操作
如果你真的想用 await
考虑你的代码,你可以像这样使用 scala async:
import scala.async.Async._
def annualAtomTesting(peril: String, region: String) = Action.async {
async {
val results: Seq[SingleEventYear] = await(db.run(filterAnnualPerilAndRegionFillGaps(peril, region).result))
val years = results.map(_.year).toSet
val allYears = (1 to 10000).toSet
val differences = allYears diff years
val missing = differences.map(new SingleEventYear(region, peril, 0, 0, _, 0))
val intermediate = header + results.mkString("\n") + "\n" + missing.mkString("\r\n")
Ok(intermediate)
}
}
您可以在 async
块中的任何 Future
上调用 await
,它将 return 结果,也许这种方法看起来更简单,但它有局限性。它将使用宏更改为 flatMaps。 async { Ok("res") }
是类型 Future[Result]
的表达式。这允许您将它放在 Action.async {}
中并使您的代码保持异步。
这是一个相对简单的问题,我确信我遗漏了一些基本的东西。
- 我正在使用 Slick 查询数据库。
- 我知道它会返回一个序列,该序列将包含缺失值...
- 所以我想将它们添加到......但我事先不知道这些值。
然后最终生成一个 csv 文件供其他人使用...
def annualAtomTesting(peril: String , region: String) = Action { val theResult: Future[Seq[SingleEventYear]] = db.run(filterAnnualPerilAndRegionFillGaps(peril, region).result) val years = theResult.map { list => list.map(s => s.year).toSet} val allYear = (1 to 10000) toSet val dbYears = Await.result( years , Duration.Inf ) val theDifference = allYear.diff( dbYears ) val whatsMissing = theDifference.map(s => new SingleEventYear(region, peril, 0 ,0 , s, 0)) val intermediate: String = Await.result( theResult.map(result => header + result.mkString("\n") + "\n" + whatsMissing.mkString("\r\n") ), Duration.Inf ) Ok(intermediate) }
因此,从 1,2,3,4,5 的潜在系列中,我可能会从数据库查询中得到 2、4、5。此代码添加了 1 和 3...但我的理解是它会阻止所有内容,这有点顽皮。
对于我所尝试的一切,我无法在未来找到如何让 .diff 方法(这看起来是最干净的策略)在 'Future'、非阻塞上下文中运行。
我是不是漏掉了什么?
这里你只有一个 Future,你不需要创建多个 Await.result。 您可以通过切换到 Action.async:
来摆脱所有 Await.result(...) 电话Action.async {
val allYear = (1 to 10000).toSet
val intermediate:Future[String] = for (
res <- db.run(filterAnnualPerilAndRegionFillGaps(peril, region).result)
) yield (
header + res.mkString("\n") + "\n" +
allYear.diff(res.map (s => s.year).toSet).map(s => new SingleEventYear(region, peril, 0 ,0 , s, 0)).mkString("\r\n")
)
intermediate.map(item => Ok(item))
}
这是如何执行此操作的另一个示例:
def annualAtomTesting(peril: String, region: String) = Action.async {
for {
results <- db.run(filterAnnualPerilAndRegionFillGaps(peril, region).result)
years = results.map(_.year).toSet
allYears = (1 to 10000).toSet
differences = allYears diff years
missing = differences.map(new SingleEventYear(region, peril, 0, 0, _, 0))
intermediate = header + results.mkString("\n") + "\n" + missing.mkString("\r\n")
} yield Ok(intermediate)
}
您不应在生产代码中使用 Await
。 Play 允许您使用需要 return Future[Result]
而不是 Result
.
如果你真的想用 await
考虑你的代码,你可以像这样使用 scala async:
import scala.async.Async._
def annualAtomTesting(peril: String, region: String) = Action.async {
async {
val results: Seq[SingleEventYear] = await(db.run(filterAnnualPerilAndRegionFillGaps(peril, region).result))
val years = results.map(_.year).toSet
val allYears = (1 to 10000).toSet
val differences = allYears diff years
val missing = differences.map(new SingleEventYear(region, peril, 0, 0, _, 0))
val intermediate = header + results.mkString("\n") + "\n" + missing.mkString("\r\n")
Ok(intermediate)
}
}
您可以在 async
块中的任何 Future
上调用 await
,它将 return 结果,也许这种方法看起来更简单,但它有局限性。它将使用宏更改为 flatMaps。 async { Ok("res") }
是类型 Future[Result]
的表达式。这允许您将它放在 Action.async {}
中并使您的代码保持异步。