Scala 无标记结尾中的parSequence和parTraverse

Scala 无标记结尾中的parSequence和parTraverse,scala,cats-effect,Scala,Cats Effect,使用无标记final(不使用IO,而是使用泛型F)我如何对以下内容进行抽象: def doSomething(s: String): IO[Unit] = ??? List("authMethods", "secretEngines", "plugins", "CAs", "common").parTraverse(doSomething) import cats.{Applicative, Parallel} import cats.instances.list._ import cats

使用无标记final(不使用IO,而是使用泛型F)我如何对以下内容进行抽象:

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

List("authMethods", "secretEngines", "plugins", "CAs", "common").parTraverse(doSomething)
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)
}
我能得到的最接近的方法是从并发对象中使用
parTraverseN
,但我假设它将并发运行,而不是并行运行(如中所示)。它还迫使我选择一个
n
,其中as
parTraverse
没有

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


理想情况下,假设
doSomething
返回
IO[Unit]
,我想用正确的typeclass实例将
parTraverse\uucode>抽象为
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\uu
,所需的最小更改如下:

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

List("authMethods", "secretEngines", "plugins", "CAs", "common").parTraverse(doSomething)
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)
并跳过
语法
导入。这两种方法都需要
列表的
可折叠的
实例(此处由
cats.instances.List.\ucode>导入提供,在中不再需要导入),以及
F
并行
实例,您可以通过
P
约束获得该实例

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

不过,这个答案需要一些脚注。第一个问题是,
parTraverse\uuu
没有像
parTraverseN
那样指定一个界限,这实际上可能不是一件好事,而且可能会导致内存过度使用,等等。(但这将取决于列表的预期大小和
doSomething
正在做的工作类型,可能超出了问题的范围)

第二个脚注是,
parallel
type类意义上的“parallel”比Cats“并发基础”中并行与并发区别中的“parallel”更为普遍文档。
Parallel
type类模拟了一种非常通用的逻辑并行性,例如,它还包括以下内容:

我假设它将并发运行,而不是并行运行(如中所示)


…您的假设是正确的,但并不完全是因为
parTraverseN
方法启用的是
Concurrent
而不是
Parallel
;请注意
Concurrent.parTraverseN
仍然需要
Parallel
实例。当您在
cats.effect.Concurrent
,您应该考虑并发,而不是“并发基础”意义上的“并行”。

在我下面的回答中,我假设您的意思是“
doSomething
返回
F[Unit]
”在最后一段中?如果
par
Parallel
类型类在
cats.effect.Concurrent
的上下文中表示并发,我可以假设
par
Parallel
的上下文中表示并行吗?在您的解决方案中,所有导入都来自cats而不是cats effect.Concurrent,cats能在其上并行运行吗它自己,也就是说,不需要猫效应机制?我缺少什么?我建议看一看。
cats。并行
本身是一个非常普遍的东西,它根本不是“运行”任何东西。
E,*]
都有一个
并行
实例,例如,在这个上下文中,
并行
意味着“合并这些验证操作结果并累积错误”,而不必说明计算是按顺序进行还是并行进行,也不必说明它们在哪个线程上运行。