我想合并多个应该并行运行的IO
值。
val io1: IO[Int] = ???
val io2: IO[Int] = ???
如我所见,我必须选择:
val parallelSum1: IO[Int] = for {
fiber1 <- io1.start
fiber2 <- io2.start
i1 <- fiber1.join
i2 <- fiber2.join
} yield i1 + i2
Parallel
的{{1}}实例与IO
(或其兄弟姐妹之一,例如parMapN
,parTraverse
,parSequence
等)一起使用
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
我们感谢您的指导:)
阿米塔伊
答案 0 :(得分:1)
我想组合多个应该独立运行的IO值 平行。
我查看它的方式是为了弄清楚“我何时使用哪个?”,我们需要返回旧的parallel vs concurrent discussion,基本上可以归结为(引用可接受的答案):>
并发性是指可以在其中启动,运行和完成两个或多个任务的时间 重叠的时间段。 不一定意味着他们会 两者都同时运行。例如,在 单核计算机。
并行化是指任务实际上在同一时间(例如,在 多核处理器。
当我们进行类似IO的操作(例如,通过有线方式创建呼叫或与磁盘进行交谈)时,我们经常喜欢提供并发示例。
问题是,当您说要“并行”执行时,您想要哪个?是前者还是后者?
如果我们指的是前者,那么使用Concurrent[F]
既可以通过签名传达意图,也可以提供适当的执行语义。如果是后者,例如,我们想并行处理一组元素,那么最好使用Parallel[F, G]
。
当我们考虑关于IO
的语义时,这常常会造成混乱,因为它同时具有Parallel
和Concurrent
的两个实例,并且我们大多使用它来不透明地定义副作用操作。
请注意,Parallel
之所以采用两个一元类型构造函数是因为这样的事实:M
(在Parallel[M[_], F[_]]
中)始终是一个Monad
实例,并且我们需要一种方法来证明Monad对于并行执行也具有Applicative[F]
实例,因为当我们想到Monad时,我们总是在谈论顺序执行语义。