2011-01-02 8 views
29

Ich versuche, wir zu verstehen, warum alle Teile des Standardbeispielcode benötigen:Warum brauchen wir 'Seq' oder 'Pseq' mit 'Par' in Haskell?

a `par` b `pseq` a+b 

Warum werden die folgenden nicht ausreichen?

a `par` b `par` a+b 

Der obige Ausdruck scheint sehr anschaulich: Versuchen sowohl a und b parallel zu bewerten und gibt das Ergebnis a+b. Ist das nur der Grund der Effizienz: Die zweite Version würde zweimal anstatt einmal entflammen?

Wie wäre es mit der folgenden, prägnanteren Version?

a `par` a+b 

Warum sollten wir sicherstellen müssen, dass b vor a+b wie im Original, Standard-Code ausgewertet wird?

Antwort

29

Ok. Ich denke, das folgende Papier beantwortet meine Frage: http://community.haskell.org/~simonmar/papers/threadscope.pdf

Zusammengefasst das Problem mit

a `par` b `par` a+b 

und

a `par` a+b 

ist der Mangel an Ordnung der Auswertung. In beiden Versionen arbeitet der Hauptthread sofort an a (oder manchmal b), was dazu führt, dass die Funken sofort "verschwinden", da kein Thread mehr gestartet werden muss, um zu bewerten, was der Hauptthread bereits begonnen hat.

Die ursprüngliche Version

a `par` b `pseq` a+b 

sorgt der Hauptthread auf bvora+b (a stattdessen würde oder sonst haben damit begonnen, Auswertung) arbeitet und damit eine Chance für die Funken a geben in einem Thread zu materialisieren für parallele Auswertung.

+6

Dies ist richtig und erklärt auch, warum 'seq' für dieses Problem nicht ausreicht. 'seq' gibt keine Garantie für die Reihenfolge der Auswertung. In 'seq b (a + b)' kann der Haupt-Thread 'a' vor 'b' auswerten, solange 'b' in WHNF ist, wenn '(a + b)' ausgewertet wird. –

+2

Ich sehe nicht, wie dieses Argument beschreibt das Problem mit 'par a (par b (a + b))' - sicher, entweder 'a' oder 'b' wird sofort ausgewertet, und der entsprechende Funke wird verpuffen, aber der andere Funke sollte sehr lebendig sein und Parallelität erzeugen. Natürlich ist es nicht die effizienteste Art, dies zu tun, wenn man einen Funken zündet, aber es funktioniert und überlässt die Frage der Evaluierungsreihenfolge dem Compiler. – gereeter

+0

Im Falle von 'par a (a + b)' ist es immer noch möglich, eine "glückliche" Parallelisierung zu erhalten, wenn die Laufzeit stattdessen zuerst "b" wählt. Dann wird der 'a'-Funke nicht zerstreut. Dies wird im PDF erwähnt: community.haskell.org/~simimonmar/papers/threadscope.pdf (Seite 2) – CMCDragonkai

16
a `par` b `par` a+b 

wird a und b parallel bewerten und gibt a + b, ja.

jedoch die pseq dort sorgt für a und b ausgewertet werden, bevor a + b ist. Weitere Informationen zu diesem Thema finden Sie unter this link.

6

a `par` b `par` a+b schafft sowohl für den Funken und ab, aber a+b erreicht ist unmittelbar so eine der Funken wird zischen (das heißt, es in dem Haupt-Thread ausgewertet wird). Das Problem dabei ist Effizienz, da wir einen unnötigen Funken erzeugt haben. Wenn Sie dies verwenden, um parallele Teilung & zu erobern, dann wird der Overhead Ihre Beschleunigung begrenzen.

a `par` a+b scheint besser, weil es nur einen einzigen Funken erzeugt. Wenn Sie jedoch versuchen, a vor b zu bewerten, wird der Funke für a verpuffen, und da b keinen Funken hat, wird dies zu einer sequentiellen Auswertung von a+b führen. Das Umstellen des Auftrags auf b+a würde dieses Problem lösen, aber als Code erzwingt dies keine Bestellung, und Haskell könnte dies immer noch als auswerten.

Also, wir a `par` b `pseq` a+b Auswertung von b im Hauptthread zu zwingen, bevor wir a+b zu bewerten versuchen. Dies gibt die a Funke Chance zu materialisieren, bevor wir versuchen, a+b zu bewerten, und wir haben keine unnötigen Funken erzeugt.