ami*_*ayh 9 functional-programming scala scala-cats cats-effect
我想组合多个IO应该并行独立运行的值.
val io1: IO[Int] = ???
val io2: IO[Int] = ???
Run Code Online (Sandbox Code Playgroud)
在我看来,我必须选择:
val parallelSum1: IO[Int] = for {
fiber1 <- io1.start
fiber2 <- io2.start
i1 <- fiber1.join
i2 <- fiber2.join
} yield i1 + i2
Run Code Online (Sandbox Code Playgroud)Parallel实例IO与parMapN(或它的兄弟姐妹等中的一种parTraverse,parSequence,parTupled等)
val parallelSum2: IO[Int] = (io1, io2).parMapN(_ + _)
Run Code Online (Sandbox Code Playgroud)不确定每种方法的优缺点,何时我应该选择其中一种方法.当抽象出效果类型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(_ + _)
Run Code Online (Sandbox Code Playgroud)
该Parallel类型类需要2层型构造,使得它稍微使用比较烦琐,没有上下文边界和与另外的模糊类型参数G[_]
感谢您的指导:)
Amitay
我想组合多个应该并行独立运行的 IO 值。
我的看法是,为了弄清楚“我什么时候使用哪个?”,我们需要返回旧的并行与并发讨论,这基本上归结为(引用已接受的答案):
并发是指两个或多个任务可以在重叠的时间段内启动、运行和完成。这并不一定意味着它们会同时运行。例如,单核机器上的多任务处理。
并行是指任务实际上是同时运行的,例如,在多核处理器上。
当我们进行类似 IO 的操作时,我们经常喜欢提供一个并发的例子,比如创建一个在线调用,或者与磁盘交谈。
问题是,当您说要“并行”执行时,您想要哪个,是前者还是后者?
如果我们指的是前者,那么使用Concurrent[F]两者都可以通过签名传达意图并提供正确的执行语义。如果是后者,例如,我们想要并行处理一组元素,那么使用 withParallel[F, G]将是更好的解决方案。
当我们考虑 this about 的语义时,通常会很困惑IO,因为它同时具有 forParallel和 的实例Concurrent,我们主要使用它来不透明地定义副作用操作。
作为旁注,Parallel采用两个一元类型构造函数的原因是因为M(in Parallel[M[_], F[_]]) 始终是一个Monad实例,我们需要一种方法来证明 Monad 也有一个Applicative[F]实例用于并行执行,因为当我们想到我们总是谈论顺序执行语义的 Monad。