这是一个类似的完整工作示例:
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
导入。这两种方法都需要一个Foldable
for 的实例List
(在此由 import 提供,在Cats 2.2.0cats.instances.list._
中不再需要),以及一个for 的实例,您可以通过约束获得。Parallel
F
P
(请注意,在第二个版本中不再需要Applicative
约束,但这只是因为这是一个非常简单的示例——我假设你的真实代码依赖于类似的东西,并且需要它和.)result
Sync
Parallel
不过,这个答案需要几个脚注。首先是它实际上可能不是一件好事,parTraverse_
它不会让你以这种方式指定一个界限parTraverseN
,并且可能导致过多的内存使用等(但这将取决于例如你的列表的预期大小和doSomething
正在做的工作,可能超出了问题的范围)。
第二个脚注是Parallel
类型类意义上的“并行”比 Cats“并发基础”文档中的并行与并发区别中的“并行”更通用。例如,Parallel
类型类模拟了一种非常通用的逻辑并行性,它也包含错误累积。所以当你写:
我假设这将同时运行而不是并行运行(如并行)。
...您的假设是正确的,但不完全是因为该parTraverseN
方法是 onConcurrent
而不是Parallel
; 请注意,Concurrent.parTraverseN
仍然需要一个Parallel
实例。当您在 的上下文中看到par
或Parallel
类型类时cats.effect.Concurrent
,您应该想到并发,而不是“并发基础”意义上的“并行”。