Scala 无标记结尾中的parSequence和parTraverse
使用无标记final(不使用IO,而是使用泛型F)我如何对以下内容进行抽象: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
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
,其中asparTraverse
没有
列表的大小只是一个例子,它可能要大得多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,*]
都有一个并行
实例,例如,在这个上下文中,并行
意味着“合并这些验证操作结果并累积错误”,而不必说明计算是按顺序进行还是并行进行,也不必说明它们在哪个线程上运行。