Warum werden Haskell-Listen-Comprehensions nicht parallel ausgeführt?

8

Ich mache Project Euler Problem 21 für Hausaufgaben und ich habe dieses Listenverständnis:

%Vor%

Dies dauert sehr lange (verständlich, da es 10000 ^ 2 Zahlenpaare testet). Wenn ich meine CPU-Auslastung betrachte, zeigt dies, dass nur 1 Kern verwendet wird.

Da das Listenverständnis keine Nebenwirkungen hat, besteht keine Gefahr, dass mehrere Zahlenpaare gleichzeitig getestet werden. Gibt es eine Möglichkeit, Haskell das automatisch zu machen oder, wenn nicht, wie könnte mein Code dafür modifiziert werden?

(Bearbeiten) Fehler beim Ausführen von print (amicableNumberSums using parList):

%Vor%

(Bearbeiten) Leistung der beiden vorgeschlagenen Methoden:

%Vor%

Das ist nicht so viel schneller als ich mir erhofft habe, aber ich habe jetzt die richtige Antwort auf das Problem und bis ich etwas mehr Haskell gelernt habe, reicht das aus.

    
bradleyjkemp 08.09.2014, 20:02
quelle

2 Antworten

5

@ bheklilrs Antwort behandelt die allgemeine Methode der Parallelisierung von Strategien, aber wie ich im obigen Kommentar angedeutet habe, zwingt die Art, wie das ursprüngliche Listenverständnis geschrieben wird, alle amicable -Tests dazu, bevor eine parList -basierte Strategie darauf stattfinden kann gehe zu seinen Elementen und fang an, sie zu bewerten, also denke ich nicht, dass @ bheklilrs Code in diesem speziellen Fall gut funktionieren wird.

Hier ist mein Vorschlag für eine Verbesserung. Sie müssen Ihr Listenverständnis neu schreiben, so dass es die Arbeit in gut definierte und unabhängige Stücke z. durch Kombinieren der x -Werte in Zwischenlisten. Zum Beispiel kann es äquivalent geschrieben werden als

%Vor%

Nun können Sie eine parallele Auswertungsstrategie zwischen dem Verständnis und der endgültigen concat setzen:

%Vor%

(Ich benutze rdeepseq hier, weil die Elemente der vorkonfigierten Liste ebenfalls Listen sind und wir alle ihre Elemente, die ganze Zahlen sind, auswerten wollen.)

    
Ørjan Johansen 09.09.2014, 10:59
quelle
20

Hier ist ein einfaches Beispiel:

%Vor%

Wie würdest du das parallelisieren? Wie würdest du das auf ein Listenverständnis verallgemeinern, um zu entscheiden, ob es parallelisiert werden kann? Was ist mit einem anderen Verständnis der Liste über eine Liste, die unendlich ist und einen neuen Thread für jedes Element auslöst, würde das Erzeugen von unendlichen Threads bedeuten. Was ist, wenn es tatsächlich viel schneller ist, die Liste sequenziell zu berechnen, da der Threading-Overhead zu groß ist und die Berechnung verlangsamt? Was ist, wenn nur die ersten 10 Elemente der Liste benötigt werden? Es wäre nicht sehr gut, die ganze Liste gierig zu berechnen, wenn ein kleiner Bruchteil erforderlich ist.

Stattdessen hat GHC beschlossen, dem Programmierer die Möglichkeit zu geben, wann und wie eine Listenberechnung parallelisiert werden soll. Anstatt Dinge implizit für Sie zu tun, können Sie mit dem Modul Control.Parallel.Strategies auswählen, wie es gemacht wird:

%Vor%

Oder berechnen Sie Teile der Liste parallel:

%Vor%

Beachten Sie, dass Sie seq und co verwenden müssen. um Ihre Daten zur richtigen Zeit in NF zu bekommen.

Die API, die von Control.Parallel.Strategies bereitgestellt wird, gibt Ihnen die Möglichkeit, verschiedene Möglichkeiten zum Berechnen einer reinen Datenstruktur parallel zu definieren, und zwar unabhängig von der Datenstruktur selbst oder anderen Algorithmen. Dies steht im krassen Gegensatz zu den meisten anderen Programmiersprachen, die Sie zwingen, Ihre Parallelität stark mit Ihren anderen Algorithmen zu verbinden, oder sogar wie die Struktur aufgebaut ist. Ich empfehle sehr, Simon Marlows Parallel und Concurrent Haskell zu lesen (es ist kostenlos online!), Was viel besser ist Job, als ich erklären kann, wie es funktioniert und wie man es benutzt.

    
bheklilr 08.09.2014 20:13
quelle