【问题标题】:Changing my blocking play / scala /slick algorithm not to block更改我的阻塞播放 / scala / slick 算法不阻塞
【发布时间】:2016-02-29 06:22:21
【问题描述】:

这是一个相对简单的问题,我确定我缺少一些基本的东西。

  • 我正在使用 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 方法(看起来像最干净的策略)在“未来”的非阻塞上下文中运行。

我错过了什么吗?

【问题讨论】:

  • P.s 这个算法是“正确的”,即产生正确的输出,但它很痒...我讨厌 :-)...
  • P.P.S 我对其中一些想法比较陌生,所以如果代码很臭,请不要伤害我!

标签: scala playframework-2.0 scalability future slick-3.0


【解决方案1】:

这里你只有一个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))
}

【讨论】:

    【解决方案2】:

    这是另一个如何做到这一点的例子:

    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 允许您使用要求您返回 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,它会返回结果,也许这种方法看起来更容易,但它有局限性。它将使用宏更改为 flatMaps。 async { Ok("res") }Future[Result] 类型的表达式。这允许您将其放入 Action.async {} 并保持您的代码异步。

    【讨论】:

      猜你喜欢
      • 2013-10-22
      • 1970-01-01
      • 2014-05-25
      • 1970-01-01
      • 2012-02-20
      • 1970-01-01
      • 1970-01-01
      • 2012-08-14
      • 2016-07-06
      相关资源
      最近更新 更多