简体   繁体   English

无标记决赛中的 parSequence 和 parTraverse

[英]parSequence and parTraverse in tagless final

Using tagless final (without using IO, but rather a generic F) how can I abstract over something like this:使用无标签最终(不使用 IO,而是使用通用 F)我如何抽象这样的东西:

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

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

The closest I can get is using parTraverseN from the Concurrent object, but I assume this will run concurrently instead of in parallel (as in parallelism ).我能得到的最接近的是使用来自 Concurrent parTraverseN的 parTraverseN,但我认为这将同时运行而不是并行运行(如并行)。 It also forces me to choose an n where as parTraverse does not.它还迫使我选择一个n ,而parTraverse没有。

The size of the list is just an example, it could be way bigger.列表的大小只是一个例子,它可能会更大。 doSomething is a pure function, multiple executions of it can run in parallel without problems. doSomething是一个纯 function,它的多次执行可以并行运行而不会出现问题。

Ideally, given that doSomething returns IO[Unit] I would like to abstract over parTraverse_ to an F with the correct typeclass instance.理想情况下,鉴于doSomething返回IO[Unit] ,我想将parTraverse_抽象为具有正确类型类实例的F

Here's a similar complete working example:这是一个类似的完整工作示例:

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)
}

If you want to use parTraverse_ here, the minimal changes necessary would look something like this:如果您想在此处使用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)
}

Alternatively you could use Parallel.parTraverse_(items)(doSomething) and skip the syntax import.或者,您可以使用Parallel.parTraverse_(items)(doSomething)并跳过syntax导入。 Both approaches require a Foldable instance for List (provided here by the cats.instances.list._ import, which will no longer be necessary in Cats 2.2.0 ), and a Parallel instance for F , which you get via the P constraint.这两种方法都需要ListFoldable实例(此处由cats.instances.list._导入提供,在Cats 2.2.0中不再需要),以及FParallel实例,您可以通过P约束获得。

(Note that the Applicative constraint on result is no longer necessary in the second version, but that's only because this is a very simple example—I'm assuming your real code relies on something like Sync instead, and will need both that and Parallel .) (请注意,在第二个版本中不再需要对resultApplicative约束,但这只是因为这是一个非常简单的示例——我假设您的真实代码依赖于Sync之类的东西,并且需要它和Parallel 。 )

This answer needs a couple of footnotes, though.不过,这个答案需要几个脚注。 The first is that it might not actually be a good thing that parTraverse_ doesn't make you specify a bound in the way that parTraverseN does, and may result in excessive memory use, etc. (but this will depend on eg the expected size of your lists and the kind of work doSomething is doing, and is probably outside the scope of the question).首先是parTraverse_不会让您以parTraverseN的方式指定边界实际上可能不是一件好事,并且可能导致过度使用 memory 等(但这将取决于例如预期的大小您的列表和doSomething正在做的工作,可能不在问题的 scope 范围内)。

The second footnote is that "parallel" in the sense of the Parallel type class is more general than the "parallel" in the parallel-vs.-concurrent distinction in the Cats "Concurrency Basics" document.第二个脚注是Parallel类型 class 意义上的“并行”比 Cats“并发基础”文档中的并行与并发区别中的“并行”更普遍。 The Parallel type class models a very generic kind of logical parallelism that also encompasses error accumulation , for example.例如, Parallel类型 class 模拟了一种非常通用的逻辑并行性,它也包含错误累积 So when you write:所以当你写:

I assume this will run concurrently instead of in parallel (as in parallelism ).我假设这将同时运行而不是并行运行(如并行)。

…your assumption is correct, but not exactly because the parTraverseN method is on Concurrent instead of Parallel ; …您的假设是正确的,但不完全是因为parTraverseN方法是Concurrent而不是Parallel note that Concurrent.parTraverseN still requires a Parallel instance.注意Concurrent.parTraverseN仍然需要一个Parallel实例。 When you see par or the Parallel type class in the context of cats.effect.Concurrent , you should think of concurrency, not "parallelism" in the "Concurrency Basics" sense.当您在 cat.effect.Concurrent 的上下文中看到parParallel类型cats.effect.Concurrent时,您应该想到并发,而不是“并发基础”意义上的“并行”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM