[英]parSequence and parTraverse in tagless final
使用無標簽最終(不使用 IO,而是使用通用 F)我如何抽象這樣的東西:
def doSomething(s: String): IO[Unit] = ???
List("authMethods", "secretEngines", "plugins", "CAs", "common").parTraverse(doSomething)
我能得到的最接近的是使用來自 Concurrent parTraverseN
的 parTraverseN,但我認為這將同時運行而不是並行運行(如並行)。 它還迫使我選擇一個n
,而parTraverse
沒有。
列表的大小只是一個例子,它可能會更大。 doSomething
是一個純 function,它的多次執行可以並行運行而不會出現問題。
理想情況下,鑒於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)
}
如果您想在此處使用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中不再需要),以及F
的Parallel
實例,您可以通過P
約束獲得。
(請注意,在第二個版本中不再需要對result
的Applicative
約束,但這只是因為這是一個非常簡單的示例——我假設您的真實代碼依賴於Sync
之類的東西,並且需要它和Parallel
。 )
不過,這個答案需要幾個腳注。 首先是parTraverse_
不會讓您以parTraverseN
的方式指定邊界實際上可能不是一件好事,並且可能導致過度使用 memory 等(但這將取決於例如預期的大小您的列表和doSomething
正在做的工作,可能不在問題的 scope 范圍內)。
第二個腳注是Parallel
類型 class 意義上的“並行”比 Cats“並發基礎”文檔中的並行與並發區別中的“並行”更普遍。 例如, Parallel
類型 class 模擬了一種非常通用的邏輯並行性,它也包含錯誤累積。 所以當你寫:
我假設這將同時運行而不是並行運行(如並行)。
…您的假設是正確的,但不完全是因為parTraverseN
方法是Concurrent
而不是Parallel
; 注意Concurrent.parTraverseN
仍然需要一個Parallel
實例。 當您在 cat.effect.Concurrent 的上下文中看到par
或Parallel
類型cats.effect.Concurrent
時,您應該想到並發,而不是“並發基礎”意義上的“並行”。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.