使用 tagless final(不使用 IO,而是使用通用 F)我如何抽象出这样的东西:
def doSomething(s: String): IO[Unit] = ???
List("authMethods", "secretEngines", "plugins", "CAs", "common").parTraverse(doSomething)
Run Code Online (Sandbox Code Playgroud)
我能得到的最接近的是parTraverseN从 Concurrent 对象中使用,但我认为这将并发运行而不是并行运行(如在parallelism 中)。这也迫使我选择一个nwhere as parTraversenot。
列表的大小只是一个例子,它可能更大。doSomething是一个纯函数,它的多次执行可以毫无问题地并行运行。
理想情况下,鉴于doSomething返回,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)
}
Run Code Online (Sandbox Code Playgroud)
如果您想在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)
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以使用Parallel.parTraverse_(items)(doSomething)并跳过syntax导入。这两种方法都需要一个Foldablefor 实例List(由cats.instances.list._导入提供,在Cats 2.2.0 中不再需要)和一个Parallelfor 实例F,您可以通过P约束获得它。
(请注意,在第二个版本中不再需要Applicative约束result,但这只是因为这是一个非常简单的例子——我假设你的真实代码依赖于类似的东西Sync,并且需要它和Parallel。)
不过,这个答案需要几个脚注。第一个是它实际上可能不是一件好事,parTraverse_它不会让您以这种方式指定界限parTraverseN,并且可能导致过度使用内存等(但这将取决于例如您的列表的预期大小以及doSomething正在进行的工作类型,可能超出了问题的范围)。
第二个脚注是Parallel类型类意义上的“并行”比 Cats“并发基础”文档中并行与并发区别中的“并行”更通用。例如,Parallel类型类模拟了一种非常通用的逻辑并行性,它也包含错误累积。所以当你写:
我假设这将同时运行而不是并行运行(如在parallelism 中)。
...你的假设是正确的,但不完全是因为该parTraverseN方法是 onConcurrent而不是Parallel; 请注意,Concurrent.parTraverseN仍然需要一个Parallel实例。当您在 的上下文中看到par或Parallel类型类时cats.effect.Concurrent,您应该想到并发,而不是“并发基础”意义上的“并行”。
| 归档时间: |
|
| 查看次数: |
1050 次 |
| 最近记录: |