无标签决赛中的 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
导入。这两种方法都需要 List
的 Foldable
实例(此处由 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
的上下文中看到 par
或 Parallel
类型 class 时,您应该想到并发,而不是 "Concurrency Basics" 中的 "parallelism"感觉。
使用 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
导入。这两种方法都需要 List
的 Foldable
实例(此处由 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
的上下文中看到 par
或 Parallel
类型 class 时,您应该想到并发,而不是 "Concurrency Basics" 中的 "parallelism"感觉。