2016-06-16 13 views
2

これは愚かな質問ではないか、私は何か明白でないことを願っています。私が行くのユニットテストを書いたScalaでの並列処理パターン

object parallelism { 
    val forkJoinPool = new ForkJoinPool 

    abstract class TaskScheduler { 
    def schedule[T](body: => T): ForkJoinTask[T] 
    def parallel[A, B](taskA: => A, taskB: => B): (A, B) = { 
     val right = task { 
     taskB 
     } 
     val left = taskA 
     (left, right.join()) 
    } 
    } 

    class DefaultTaskScheduler extends TaskScheduler { 
    def schedule[T](body: => T): ForkJoinTask[T] = { 
     val t = new RecursiveTask[T] { 
     def compute = body 
     } 
     Thread.currentThread match { 
     case wt: ForkJoinWorkerThread => t.fork() 
     case _ => forkJoinPool.execute(t) 
     } 
     t 
    } 
    } 

    val scheduler = 
    new DynamicVariable[TaskScheduler](new DefaultTaskScheduler) 

    def task[T](body: => T): ForkJoinTask[T] = { 
    scheduler.value.schedule(body) 
    } 

    def parallel[A, B](taskA: => A, taskB: => B): (A, B) = { 
    scheduler.value.parallel(taskA, taskB) 
    } 
} 

:私はコーセラ並列プログラミングのクラスを以下のよ、と週1で、それらを並列にタスクを実行するには、次のコードを(私は私の中に入力されたことから、多少異なる場合があります)持っていますこのようなsoemthing:最初のテストで

test("Test two task parallelizer") { 
    val (r1, t1) = timed { 
     (sieveOfEratosthenes(100000), 
     sieveOfEratosthenes(100000)) 
    } 

    val (r2, t2) = timed { 
     parallel (
     sieveOfEratosthenes(100000), 
     sieveOfEratosthenes(100000) 
    ) 
    }  
    assert(t2 < t1) 
    } 

    test("Test four task parallelizer") { 
    val (r1, t1) = timed { 
     (sieveOfEratosthenes(100000), 
     sieveOfEratosthenes(100000), 
     sieveOfEratosthenes(100000), 
     sieveOfEratosthenes(100000)) 
    } 

    val (r2, t2) = timed { 
     parallel (
     parallel (
      sieveOfEratosthenes(100000), 
      sieveOfEratosthenes(100000) 
     ), 
     parallel (
      sieveOfEratosthenes(100000), 
      sieveOfEratosthenes(100000) 
     ) 

    ) 
    } 
    assert(t2 < t1) 
} 

、私は良い貯蓄(50ミリ秒まで300ミリ秒)の節約を得るが、第二のテストで、私は20msの削減について取得し、私は多くの場合、時間は十分にそれを実行した場合実際にテストを増やしたり失敗したりするかもしれません。

試験方法は、最初のバージョンはここからである(「時限」で返されるタプルの2番目の値はミリ秒単位の時間です):https://rosettacode.org/wiki/Sieve_of_Eratosthenes#Scala

誰かが第二のテストで何が起こっているのかを教えてできますか?それが重要なら、私は単一のCPU、クアッドコアi5で動作しています。作成するスレッドの数は、この特定のテストでは大きな違いはありません。

+0

あなたが選んだ 'sieveOfEratosthenes'の実装は、既に並列化されているようです(' ParSet'を使っているもの)、それをさらに並列化することは助けになりません。あなたが最初のテストで見るスピードアップはおそらくJITウォームアップ(野生の推測)です。 –

+0

私はもっと世俗的な(非並列の)何かを試して、JITウォーミングアップを追加します。 –

+0

スワップしてもう一度やり直してください。 2回目のテストでスピードアップが見えますか? –

答えて

1

あなたが選択したsieveOfEratosthenesの実装は、すでに並列化されています(ParSetを使用しています)ので、それをさらに並列化しても役立たないでしょう。

最初のテストで表示されるスピードアップは、おそらくJITウォームアップです。

+0

ありがとうございます。今私はテストの前にウォームアップする方法を理解する必要があるので、私は再び同じミスをしません! :) –

+2

クラスでお勧めするhttps://scalameter.github.io/を使用してください:) –