Scala cats效果:使用'ParseSequence'时无法看到执行时间的减少`
我是新来的猫效应库,我遇到了一个并行执行的问题。我有一个我认为会受益的应用程序,但当我在一个玩具构造上测试这个想法时,我似乎看不到执行时间上的差异。我觉得我一定是错过了一些对别人来说很明显的东西,所以我想我应该试试运气。在下面的代码中,我有两个跨数字序列求和的实现(Scala cats效果:使用'ParseSequence'时无法看到执行时间的减少`,scala,parallel-processing,cats-effect,Scala,Parallel Processing,Cats Effect,我是新来的猫效应库,我遇到了一个并行执行的问题。我有一个我认为会受益的应用程序,但当我在一个玩具构造上测试这个想法时,我似乎看不到执行时间上的差异。我觉得我一定是错过了一些对别人来说很明显的东西,所以我想我应该试试运气。在下面的代码中,我有两个跨数字序列求和的实现(addInSequence和addInParallel),都是在run()函数中执行的。当我运行程序时,我注意到它们的运行时间几乎相同。我错过了什么明显的东西吗 导入cats.Monoid 导入cats.effect.{ExitCod
addInSequence
和addInParallel
),都是在run()
函数中执行的。当我运行程序时,我注意到它们的运行时间几乎相同。我错过了什么明显的东西吗
导入cats.Monoid
导入cats.effect.{ExitCode,IO,IOApp}
进口猫_
导入scala.concurrent.duration.{FiniteDuration,TimeUnit}
案例类结果[A](值:A,二次选择:双精度)
目标结果{
def total[A](结果:Seq[Result[A]])(隐式mon:Monoid[A]):结果[A]={
val out:Result[A]=results.foldLeft(Result.empty[A]){
(输出:结果[A],下一个:结果[A])=>
val newValue:A=mon.combine(out.value,next.value)
val aggTime:Double=out.secondsElapsed+next.secondsElapsed
结果(newValue、aggTime)
}
出来
}
def empty[A](隐式mon:Monoid[A]):结果[A]=结果(mon.empty,0d)
隐式val intAddMon:Monoid[Int]=新的Monoid[Int]{
覆盖def empty:Int=0
覆盖def联合收割机(x:Int,y:Int):Int=x+y
}
}
对象并行映射扩展IOApp{
def slowAdd(nums:Seq[Int]):Int=nums.foldLeft(0){
(out:Int,next:Int)=>
val seconds:TimeUnit=java.util.concurrent.TimeUnit.seconds
val延迟:IO[单位]=IO.睡眠(有限持续时间(1L,秒))
delay.unsafeRunSync()
出+下一个
}
def timeIt[A](操作:=>A):结果[A]={
val start:Double=System.nanoTime/1e9
val out:A=op
val stop:Double=System.nanoTime/1e9
结果(输出、停止-启动)
}
def附加序列(第一个:序列[Int],第二个:序列[Int],第三个:序列[Int]):IO[结果[Int]={
val partialSums:Seq[Result[Int]=Seq(first,second,third).map(ns=>timeIt(slowAdd(ns)))
IO(结果总计(部分))
}
def addInParallel(第一个:Seq[Int],第二个:Seq[Int],第三个:Seq[Int]):IO[Result[Int]={
val ioSeq:List[IO[Result[Int]]]=List(第一、第二、第三).map(ns=>IO(timeIt(slowAdd(ns)))
val sums:IO[List[Result[Int]]]=ioSeq.parSequence
为了{
partialSums两件事:
并行操作不能保证总是更快。如果顺序操作很短,则分派到多个线程以及稍后收集所有结果的开销可能大于加速
看一看您正在测量的内容。您有一个顺序操作可以完成X工作量,或者有三个操作可以完成X/3工作量。您测量所有这些操作,然后比较:顺序运行X的时间与运行X/3的总时间在三个任务中的工作量。如果顺序运行大约需要3秒钟,则每次并行运行需要3秒钟根据这个逻辑,两个版本都需要3秒,这可能是对CPU使用时间的测量,但如果我们测量从开始工作到结束的时间,则不完全正确
如果我运行你的代码,我会
@ ParallelMap.main(Array[String]())
List((Serial,Result(30,12.058612958004232)), (Parallel,Result(30,12.005087116995128)))
但是,如果改为运行此代码:
object ParallelMap extends IOApp {
def slowAdd(nums: Seq[Int]): Int = nums.foldLeft(0) {
(out: Int, next: Int) =>
val seconds: TimeUnit = java.util.concurrent.TimeUnit.SECONDS
val delay: IO[Unit] = IO.sleep(FiniteDuration(1L, seconds))
delay.unsafeRunSync()
out + next
}
def timeIO[A](op: IO[A]): IO[Result[A]] = for {
start <- IO(System.nanoTime / 1e9)
out <- op
stop = System.nanoTime / 1e9
} yield Result(out, stop - start)
def addInSequence(first: Seq[Int], second: Seq[Int], third: Seq[Int]): IO[Result[Int]] = {
timeIO(IO(List(first, second, third).map(ns => slowAdd(ns)).sum))
}
def addInParallel(first: Seq[Int], second: Seq[Int], third: Seq[Int]): IO[Result[Int]] = {
// I changed is as little as possible so that you would still see
// similarity to your code, but normally I would write
// .parTraverse(f) instead of .map(f).parSequence
timeIO(List(first, second, third).map(ns => IO(slowAdd(ns))).parSequence.map(_.sum))
}
def run(args: List[String]): IO[ExitCode] = {
val nums: Seq[Int] = 1 to 4
val results: IO[Seq[(String, Result[Int])]] = for {
serial <- addInSequence(nums, nums, nums)
parallel <- addInParallel(nums, nums, nums)
} yield Seq(("Serial", serial), ("Parallel", parallel))
val report: IO[Unit] = results.map(println)
report.unsafeRunSync()
IO(ExitCode.Success)
}
}
这表明并行计算的速度是顺序计算的3倍。您将对所有单独任务的执行时间求和。显然,无论这些任务是顺序运行还是并行运行,您都会得到大致相同的结果。这是完全有道理的。我确信我构建了并行计算谢谢你的评论。
@ ParallelMap.main(Array[String]())
List((Serial,Result(30,12.006349742005114)), (Parallel,Result(30,4.003020468982868)))