猫效果-独立效果的平行组成

时间:2019-01-13 13:35:38

标签: scala functional-programming scala-cats cats-effect

我想合并多个应该并行运行的IO值。

val io1: IO[Int] = ???
val io2: IO[Int] = ???

如我所见,我必须选择:

  1. 使用具有叉形接头图案的cats-effect纤维
    val parallelSum1: IO[Int] = for {
      fiber1 <- io1.start
      fiber2 <- io2.start
      i1 <- fiber1.join
      i2 <- fiber2.join
    } yield i1 + i2
    
  2. Parallel的{​​{1}}实例与IO(或其兄弟姐妹之一,例如parMapNparTraverseparSequence等)一起使用
    parTupled

不确定每种方法的优缺点,以及何时应选择一种方法。在效果类型val parallelSum2: IO[Int] = (io1, io2).parMapN(_ + _) (无标签最终样式)上抽象时,这变得更加棘手:

IO

def io1[F[_]]: F[Int] = ??? def io2[F[_]]: F[Int] = ??? def parallelSum1[F[_]: Concurrent]: F[Int] = for { fiber1 <- io1[F].start fiber2 <- io2[F].start i1 <- fiber1.join i2 <- fiber2.join } yield i1 + i2 def parallelSum2[F[_], G[_]](implicit parallel: Parallel[F, G]): F[Int] = (io1[F], io2[F]).parMapN(_ + _) 类型类需要2个类型构造函数,使用起来比较麻烦,没有上下文限制,并且带有额外的模糊类型参数Parallel

我们感谢您的指导:)

阿米塔伊

1 个答案:

答案 0 :(得分:1)

  

我想组合多个应该独立运行的IO值   平行。

我查看它的方式是为了弄清楚“我何时使用哪个?”,我们需要返回旧的parallel vs concurrent discussion,基本上可以归结为(引用可接受的答案):

  

并发性是指可以在其中启动,运行和完成两个或多个任务的时间   重叠的时间段。 不一定意味着他们会   两者都同时运行。例如,在   单核计算机。

     

并行化是指任务实际上在同一时间(例如,在   多核处理器。

当我们进行类似IO的操作(例如,通过有线方式创建呼叫或与磁盘进行交谈)时,我们经常喜欢提供并发示例。

问题是,当您说要“并行”执行时,您想要哪个?是前者还是后者?

如果我们指的是前者,那么使用Concurrent[F]既可以通过签名传达意图,也可以提供适当的执行语义。如果是后者,例如,我们想并行处理一组元素,那么最好使用Parallel[F, G]

当我们考虑关于IO的语义时,这常常会造成混乱,因为它同时具有ParallelConcurrent的两个实例,并且我们大多使用它来不透明地定义副作用操作。

请注意,Parallel之所以采用两个一元类型构造函数是因为这样的事实:M(在Parallel[M[_], F[_]]中)始终是一个Monad实例,并且我们需要一种方法来证明Monad对于并行执行也具有Applicative[F]实例,因为当我们想到Monad时,我们总是在谈论顺序执行语义。