2016-06-16 4 views
2

Ich hoffe, das ist keine dumme Frage oder mir fehlt etwas offensichtlich. Ich verfolge die Coursera parallele Programmierung Klasse, und in Woche 1 haben sie den folgenden Code Aufgaben parallel laufen zu lassen (können leicht voneinander abweichen, da ich meine in getippt):Parallele Bearbeitungsmuster in 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) 
    } 
} 

ich einen Komponententest geschrieben, das geht soemthing wie folgt aus:

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) 
} 

im ersten Test, bekomme ich gute Einsparungen (300 ms bis zu 50 ms) Einsparungen, aber auf dem zweiten Test, ich habe nur etwa 20 ms Einsparungen bekommen, und wenn ich laufe es oft genug, um die Zeit kann tatsächlich erhöhen und meinen Test nicht bestehen. (Der zweite Wert in dem Tupel zurückgegeben durch „timed“ ist die Zeit in Millisekunden)

Das Testverfahren ist erste Version von hier: https://rosettacode.org/wiki/Sieve_of_Eratosthenes#Scala

Kann mir jemand beibringen, was im zweiten Test ist da los? Wenn es darauf ankommt, bin ich auf einer einzigen CPU, Quad Core i5 laufen. Die Anzahl der Threads, die ich erstelle, scheint für diesen speziellen Test keinen großen Unterschied zu machen.

+0

Sieht so aus, als sei die Implementierung von 'siebOfEratosthenes', die Sie gewählt haben, bereits parallel (diejenige, die' ParSet' verwendet), so dass es nicht weiter parallelisiert wird. Die Beschleunigung, die Sie im ersten Test sehen, ist wahrscheinlich JIT Warmup (Wild Guess). –

+0

Ich werde es mit etwas mehr banal (nicht parallel) versuchen und auch einige JIT Warmup hinzufügen. –

+0

Tauschen Sie sie aus und versuchen Sie es erneut. Sehen Sie die Beschleunigung im zweiten Test? –

Antwort

1

Die Implementierung von sieveOfEratosthenes, die Sie gewählt haben, ist bereits parallel (es verwendet ParSet), so dass es weiter parallelisieren wird nicht helfen.

Die Beschleunigung, die Sie im ersten Test sehen, ist wahrscheinlich JIT Aufwärmen.

+0

Danke. Jetzt muss ich herausfinden, wie ich mich vor meinen Tests aufwärmen muss, damit ich nicht wieder denselben Fehler mache! :) –

+2

Verwenden Sie https://scalameter.github.io/ wie in der Klasse empfohlen :) –