在Doobie中并行运行查询

时间:2018-06-13 09:30:07

标签: scala functional-programming scala-cats doobie

使用Doobie可以并行运行多个查询吗?

我有以下(伪)查询:

def prepareForQuery(input: String): ConnectionIO[Unit] = ???
val gettAllResults: ConnectionIO[List[(String, BigDecimal)]] = ???
def program(input : String) : ConnectionIO[List[(String, BigDecimal)]] = for{
    _ <- prepareForQuery(input)
    r <- gettAllResults
  } yield r

我尝试的是以下内容:

import doobie._
import doobie.implicits._
import cats.implicits._
val xa = Transactor.fromDataSource[IO](myDataSource)
val result = (program(i1),program(i2)).parMapN{case (a,b) => a ++ b}
val rs = result.transact(xa).unsafeRunSync

但是,ConnectionIO没有找到NonEmptyParallel实例。

  

错误:(107,54)找不到参数p的隐含值:   cats.NonEmptyParallel [doobie.ConnectionIO,F] val result =   (程序(i1),程序(i2))。parMapN {case(a,b)=&gt; a ++ b}

我是否遗漏了一些明显或尝试无法完成的事情? 感谢

1 个答案:

答案 0 :(得分:3)

您不能在ConnectionIO monad中并行运行查询。但是,只要将它们转换为实际的运行时monad(只要它具有Parallel实例),就可以。

例如,使用cats-effect IO运行时monad:

def prepareForQuery(input: String): ConnectionIO[Unit] = ???
val gettAllResults: ConnectionIO[List[(String, BigDecimal)]] = ???
def program(input : String) : ConnectionIO[List[(String, BigDecimal)]] = for{
    _ <- prepareForQuery(input)
    r <- gettAllResults
  } yield r

将您的ConnectionIO变成IO

val program1IO: IO[List[(String, BigDecimal)]]] = program(i1).transact(xa)
val program2IO: IO[List[(String, BigDecimal)]]] = program(i2).transact(xa)

您现在有了一个可以并行执行操作的monad。

val result: IO[List[(String, BigDecimal)]]] = 
    (program1IO, program2IO).parMapN{case (a,b) => a ++ b}

要了解为什么ConnectionIO不允许您并行执行操作,我只引用tpolecat:

您不能并行运行ConnectionIO。这是一种描述连接使用的语言,该连接是线性操作序列。

在IO中使用parMapN,是的,您可以同时运行两件事,因为它们运行在不同的连接上。

没有ConnectionIO的parMapN,因为它不(也不能)具有Parallel实例。