无标签决赛中的 parSequence 和 parTraverse

parSequence and parTraverse in tagless final

使用 tagless final(不使用 IO,而是一个通用的 F)我如何抽象出这样的东西:

def doSomething(s: String): IO[Unit] = ???

List("authMethods", "secretEngines", "plugins", "CAs", "common").parTraverse(doSomething)

我能得到的最接近的是使用 Concurrent 对象中的 parTraverseN,但我认为这将同时 运行 而不是并行(如 parallelism)。它还迫使我选择 n,而 parTraverse 则没有。

列表的大小只是一个例子,它可以更大。 doSomething 是一个纯函数,多次执行它可以 运行 并行而不会出现问题。

理想情况下,鉴于 doSomething returns IO[Unit] 我想将 parTraverse_ 抽象为具有正确类型类实例的 F

这是一个类似的完整工作示例:

import cats.Applicative
import cats.instances.list._
import cats.syntax.foldable._

trait Service[F[_]] {
  val items = List("authMethods", "secretEngines", "plugins", "CAs", "common")

  def doSomething(s: String): F[Unit] = ???

  def result(implicit F: Applicative[F]): F[Unit] =
    items.traverse_(doSomething)
}

如果您想在此处使用 parTraverse_,所需的最小更改如下所示:

import cats.{Applicative, Parallel}
import cats.instances.list._
import cats.syntax.parallel._

trait Service[F[_]] {
  val items = List("authMethods", "secretEngines", "plugins", "CAs", "common")

  def doSomething(s: String): F[Unit] = ???

  def result(implicit F: Applicative[F], P: Parallel[F]): F[Unit] =
    items.parTraverse_(doSomething)
}

或者您可以使用 Parallel.parTraverse_(items)(doSomething) 并跳过 syntax 导入。这两种方法都需要 ListFoldable 实例(此处由 cats.instances.list._ 导入提供,在 Cats 2.2.0 中不再需要)和 Parallel 实例对于 F,您可以通过 P 约束获得。

(请注意,在第二个版本中不再需要 result 上的 Applicative 约束,但这只是因为这是一个非常简单的示例——我假设您的真实代码依赖于像 Sync 之类的东西,并且需要它和 Parallel。)

虽然这个答案需要几个脚注。首先是 parTraverse_ 没有让您以 parTraverseN 的方式指定界限实际上可能不是一件好事,并且可能导致过度使用内存等。(但这将取决于例如列表的预期大小和 doSomething 正在做的工作类型,并且可能超出问题的范围)。

第二个脚注是 "parallel" 在 Parallel 类型的意义上 class 比并行与并发区别中的 "parallel" 更通用在 Cats "Concurrency Basics" 文档中。例如,Parallel 类型 class 模拟了一种非常通用的逻辑并行性,它也包含 error accumulation。所以当你写:

I assume this will run concurrently instead of in parallel (as in parallelism).

…你的假设是正确的,但不完全是因为 parTraverseN 方法是在 Concurrent 而不是 Parallel 上;请注意 Concurrent.parTraverseN 仍然需要一个 Parallel 实例。当您在 cats.effect.Concurrent 的上下文中看到 parParallel 类型 class 时,您应该想到并发,而不是 "Concurrency Basics" 中的 "parallelism"感觉。