同様の完全な動作例を次に示します。
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どちらの方法でも、 のFoldableインスタンスList(ここではインポートによって提供されます。これはCats 2.2.0cats.instances.list._では不要になります) と、制約を介して取得する のインスタンスが必要です。ParallelFP
Applicative(2 番目のバージョンではon の制約resultが不要になっていることに注意してください。ただし、これは単にこれが非常に単純な例であるためです。実際のコードはSync代わりに のようなものに依存しており、それと の両方が必要になると想定していますParallel。)
ただし、この回答にはいくつかの脚注が必要です。parTraverse_1つ目は、境界を指定する方法で境界を指定しないことは実際には良いことではないparTraverseN可能性があり、過度のメモリ使用などを引き起こす可能性があることです.作業の種類doSomethingは行っており、おそらく質問の範囲外です)。
2 番目の脚注は、Parallel型クラスの意味での「並列」は、Cats の「同時実行の基本」ドキュメントの並列と同時の区別における「並列」よりも一般的であるということです。型クラスは、たとえば、エラー累積Parallelも含む非常に一般的な種類の論理的並列処理をモデル化します。だからあなたが書くとき:
これは、並列ではなく同時に実行されると思います(parallelismのように)。
…あなたの仮定は正しいですが、parTraverseNメソッドが;Concurrentの代わりにon であるため、正確ではありません。まだインスタンスが必要であるParallelことに注意してください。または のコンテキストで型クラスを見るときは、「並行処理の基本」の意味での「並列処理」ではなく、並行処理について考える必要があります。Concurrent.parTraverseNParallelparParallelcats.effect.Concurrent