4

使用无标签最终(不使用 IO,而是使用通用 F)我如何抽象这样的东西:

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

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

我能得到的最接近的是parTraverseN从 Concurrent 对象中使用,但我认为这将同时运行而不是并行运行(如在parallelism中)。它也迫使我选择一个nwhere as parTraversenot。

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

理想情况下,考虑到doSomething返回值,IO[Unit]我想抽象parTraverse_F具有正确类型类实例的一个。

4

1 回答 1

6

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

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导入。这两种方法都需要一个Foldablefor 的实例List(在此由 import 提供,在Cats 2.2.0cats.instances.list._中不再需要),以及一个for 的实例,您可以通过约束获得。ParallelFP

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

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

第二个脚注是Parallel类型类意义上的“并行”比 Cats“并发基础”文档中的并行与并发区别中的“并行”更通用。例如,Parallel类型类模拟了一种非常通用的逻辑并行性,它也包含错误累积。所以当你写:

我假设这将同时运行而不是并行运行(如并行)。

...您的假设是正确的,但不完全是因为该parTraverseN方法是 onConcurrent而不是Parallel; 请注意,Concurrent.parTraverseN仍然需要一个Parallel实例。当您在 的上下文中看到parParallel类型类时cats.effect.Concurrent,您应该想到并发,而不是“并发基础”意义上的“并行”。

于 2020-05-29T09:22:47.730 回答