Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Also ich finde es schön dass es zb in C++/Java primitive Datentypen gibt. Sie sind für mich wie kleine Helfer, wie Bauer im Schach, wie eine Ausnahme eines Regels... Alles unter ein Dach zu bringen, wie in Scala, finde ich überhaupt nicht innovativ, dafür aber ziemlich primitiv.
Tolle Ausnahme, die uns quer im restlichen Getriebe liegt! Generics mit Primitiven? Sorry, geht nicht, aber wir haben ja diese hübschen Wrapper, da können wir ganz fein hin- und herboxen. Na ja, wenigstens solange die Wrapper nicht null sind.
Und die Primitive kann man auch sooo gut verallgemeinern, sie haben ja auch einen gemeinsamen Obertyp, nämlich... Ach halt, das waren nur die Wrapper, für die es Number gibt....
Ehrlich, langsam habe ich das Gefühl, das zu langer Java-Kontakt eine Mischung aus Stockholm-Syndrom und Lobotomie auslöst...
Arguing on the net? Win or lose, you're still an ... also, kein Grund polemisch zu werden
Sicher, manche Beiträge lassen Objektivität (und Fundiertheit) vermissen, aber Es gibt unterschiedliche Ansichten und Schwerpunkte und Ziele - und Stellen, an denen man mal einen rohen array von echten bytes (ja, einfach nur 8 bit, kein Byte-Objekt) braucht. Es wäre vielleicht besser, wenn das nicht so wäre, aber die historische Entwicklung von C über C++ bis Java kann man ja nicht einfach ausblenden - und bei der Frage, ob Java diesen Erfolg gehabt hätte, wenn es nicht dieses Zugeständnis an seine C-Wurzeln gemacht hätte, ist schwerer zu beantworten, als die Frage wo oder was Scala wäre, wenn es Java nicht gegeben hätte...
dann heisst es also Scala ist mehr so eine Art Forschungssprache? Wer kommt denn sonst auf die Idee unglaublich komplizierte Dinge auf einer höheren Ebene zu beschreiben. Jetzt bitte nicht falsch verstehen, mir geht es nur um die Industrietauglichkeit von Scala im Bereich Web, Mobile (Apps) usw das was halt zur Zeit gefragt ist.
Selbst wenn es Scala erlaubt ein Problem besser zu beschreiben, bin ich mir sicher, es wird einen anderen Programmieren geben der sagen würde: "In Programmiersprache XY geht es noch einfacher und abstrakter..."
Dabei würde ich folgendes gern zitieren (was ich eigentlich oben sagen wollte):
"Ich kann der Argumentation, dass der immer kürzer werdende Code lesbarer sein soll, nicht folgen. Man braucht immer mehr implizites Wissen, um zu verstehen, was da eigentlich passiert. Was der Entwickler dann ursprünglich wollte, war dann im Zweifel nochmal etwas komplett anderes."
Damit eine Sprache wirklich große Akzeptanz erlangt ist es m.E. extrem wichtig und einer der Erfolgsfaktoren von Java, dass fremder Code leicht lesbar ist. Leider gibt es in Scala ein paar Dinge, die dem entgegenstehen. Besonders negativ wirkt sich die Verwendung von mehr oder weniger sinnvollen Zeichenkombinationen als Operatoren aus. So würde ich die Freiheit, Bezeichner als Operatoren zu verwenden, eindeutig wieder einschränken.
Besonders heute finde ich wichtig: "dass fremder Code leicht lesbar ist". Man kann nicht von jedem Programmierer erwarten (selbst wenn es nur ein Student ist) das man sich mit einer Sprache auskennt die nur bei bestimmten, speziellen Problemen eingesetzt wird.
In der Forschung, an der Uni, Profs unter sich... da geht es bestimmt, aber es ist eine andere Liga.
P.S. zum Thema kleine Helfer... du könntest einfach mal nachdenken was ich damit sagen wollte... Das war vielleicht einwenig primitiv ausgedrückt, aber leider kann das nicht komplexer und abstrakter beschreiben...
Wenn ich in einer schleife
Code:
for(int i = 0;...)
Variable i verwende, so ist es für mich viel logischer und intuitiver das i nur eine Zahl ist. Sie soll überhaupt keine anderen Eigenschaften (wozu den auch?) haben. Ich brauche kein Objekt für diese Aufgabe.
Ein Haus ist ein Objekt, eine Zahl dagegen ist für mich etwas kleines, nicht wirklich (physikalisch) existierendes. Warum muss es dann unbedingt in einer Programmiersprache so überbewertet werden?.. Nur eine Zahl, ich möchte es zu einem bestimmten Punkt auf dem Stack ablegen X-mal erhöhen und vielleicht danach nie wieder verwenden. Es ist für mich wirklich ein kleiner, elementarer Helfer.
Und die Primitive kann man auch sooo gut verallgemeinern, sie haben ja auch einen gemeinsamen Obertyp, nämlich... Ach halt, das waren nur die Wrapper, für die es Number gibt....
Falls du irgendwann auf die Idee kommts primitive Typen zu verallgemeinern, dann hast du einfach mißverstanden wo man die primitive Datentypen einsetzen soll und was deren Vorteil ist und warum sie nicht nur in Java unentbehrlich sind.
Weil hier das Stichwork Quicksort gefallen ist, schlage ich nochmal den Bogen zu einem meiner Beiträge weiter oben : Einer der Hauptgründe, weswegen ich mir Scala mal ansehen wollte, war, dass ich gehofft hatte, dass es damit möglich sein könnte, eine Domänenspezifische Sprache zu erstellen, die ähnlich kompakt und mächtig ist wie NESL. Die Frage, warum 10 Zeilen beinahe-Pseudocode (auch wenn sie ein "<%" enthalten) vorteilhaft sein können, stellt sich vielleicht gar nicht mehr, wenn die Alternative dazu aus 1700 Zeilen kryptischem Spezialcode besteht: Making Parallel Programming Easy and Portable . Das geht eben praktisch nur so schön, wenn man eben nicht mit einer for-Schleife auf einem rohen Array rumhantiert (aka Code schreibt, bei dem eine 1:1-Übersetzung in Assembler reine Fleißarbeit wäre) sondern das, was zu tun ist auf einer höheren Ebene beschreibt.
vielleicht verstehe Deinen Einwand nicht ganz, aber die 1700 Zeilen beziehen sich doch auf eine konkrete alternative rohe MPI Quicksort Implementierung. Imho ist der Vergleich so nicht fair. Würde man die 1700 MPI Zeilen in ein "void quicksort(final byte[] values)" "verstecken", wäre der Vergleich 10 Zeilen DSL vs. 1 Zeile Java. Egal wie später die Problemstellung für den Rechner formuliert wird, der Rechenaufwand ist dabei immer gleich. Und die Länge (in Codezeilen) der Aufgabenstellung (evtl. DSL) vermutlich umgekehrt proportional zu den möglichen Freiheitsgraden innerhalb der Problemstellung.
Und bei Scala kann ich mich des Eindrucks nicht erwähren, dass dabei besonders gerne abgefahrene Syntaxspielchen eingesetzt werden. Ich meine ein
Code:
#pragma omp parallel for
for (i = 0; i < N; i++)
a[i] = 2 * i;
gibt es jetzt seit bald 15 Jahren. Das ist zwar natürlich nicht so mächtig wie eine abgefahrene mit Scala umgesetzte DSL. Der Vorteil ist jedoch, dass es praktisch von jedem Schüler gelesen werden kann, welcher irgendwann und irgendwo schon mal irgendein Programm gelesen hat.
Unabhängig davon halte ich den Vorteil, den funktionale Programmierung im Bezug auf Multi/Manycore Anwendungen haben soll, für überbewertet. Damit daraus ein Vorteil für den normalen Anwendungsentwickler entsteht, müssen imho einige Randbedingungen erfüllt sein: Das Problem sollte
- überhaupt parallelisierbar sein
- eine kritische Problemgröße aufweisen (zu groß für singe core, klein genug für SMP)
- nicht trivial parallelisierbar sein (sonst gibt es effizientere Ansätze)
- nicht sowieso ständig auf IO warten (Benutzer, Daten, ..)
Also zumindest mir fällt da nicht sonderlich viel ein. Die meisten Probleme sind einfach so irrelevant das sie auch auf einem single core noch akzeptabel laufen oder lassen sich eben trivial parallelisieren. Auf der anderen Seite stehen dann doch nur noch die GPU Fetischisten (z.B. mit OpenCL) oder die Leute die richtig rocken wollen (z.B. mit OpenMP / MPI). Das sind aber absolute Nischen, nichts was für die breite Masse der Entwickler von Interesse wäre.
Was die vermeintlichen Vorteile von Scala angeht, also ich habe diesen Thread (und auch all die anderen dazu) gelesen, könnte aber leider nichts entdecken, was für eine general purpose Sprache von Bedeutung wäre. Imho ist Scala ein tolles Projekt und wird auch sicher seine Nische finden, aber als general purpose language sehe ich da nichts.
Und zum Schluss: Der oben erwähnte Abschnitt aus dem Buch Scala für Umsteiger (Seite XII ff.) ist ja wohlwollend höchstens noch polemisch zu verstehen. Ich meine z.B., "Die Befehle zur Concurrent-Programmierung liegen in OO-Sprachen auf Assembler-Niveau." WTF? Der gute Mann sollte sich vielleicht mal einen HPC Kurs in z.B. Java zu Gemüte führen (und versuchen Vergleichbares in Assembler zu realisieren), ehe er merkwürdige Thesen in Büchern niederschreibt.
Ein Haus ist ein Objekt, eine Zahl dagegen ist für mich etwas kleines, nicht wirklich (physikalisch) existierendes. Warum muss es dann unbedingt in einer Programmiersprache so überbewertet werden?.. Nur eine Zahl, ich möchte es zu einem bestimmten Punkt auf dem Stack ablegen X-mal erhöhen und vielleicht danach nie wieder verwenden. Es ist für mich wirklich ein kleiner, elementarer Helfer.
das ist aber mehr als willkuerlich dann, also was nun ein Objekt sein darf und was nicht (Zahl ist im englischen Number und schwups haben wir ein Objekt). Auch diese "aengstliche" annahme, dass man primitive Typen ja nicht als Objekt sehen sollte versteh ich nicht. Was ist schlimm wenn es nur noch eine Klasse int gibt ?
Neben den Argumenten von Landei kommt noch hinzu dass man aufgrund der Restriktion von primitiven Typen anfaengt statische Elemente einbauen zu muessen (nicht nur ich will, sondern ich muss).
Methode abs() aus Math muss eine statische Methode einer anderen Klasse sein, weil int leider damit nicht umgehen kann. Es ist aber eine Fachlichkeit einer Zahl ihren absolut Betrag zu wissen.
( aber das ist nochmal eine komplett andere Diskussion )
Zu dem quicksort bsp muss ich noch sagen dass ich eher ueberrascht bin, dass das zu lesen ist. Ich habe mich nicht sehr viel mit Scala selbst beschaeftigt, doch als Informatiker sollte man in der lage sein mit etwas denken diesen Code zu verstehen. Ich sage nicht dass man ihn so moegen muss, aber das Argument nicht verstaendlich kann ich nicht nachvollziehen
Moin,
Und zum Schluss: Der oben erwähnte Abschnitt aus dem Buch Scala für Umsteiger (Seite XII ff.) ist ja wohlwollend höchstens noch polemisch zu verstehen. Ich meine z.B., "Die Befehle zur Concurrent-Programmierung liegen in OO-Sprachen auf Assembler-Niveau." WTF? Der gute Mann sollte sich vielleicht mal einen HPC Kurs in z.B. Java zu Gemüte führen (und versuchen Vergleichbares in Assembler zu realisieren), ehe er merkwürdige Thesen in Büchern niederschreibt.
Mir ist klar was er damit aussagen wollte. ich weis zwar nicht was ein HPC Kurs ist aber ich denke den könnte man auch direkt bei dem Informatik Prof. nehmen Esser Friedrich
Ich fasse mal zusammen:
-Scala ist kryptisch und fremdartig
-Man kann nicht besser damit Entwickeln im vergleich zu Java
-Viele Scala Features sind unnötig
-Yet Another VM Language
Für mich hört sich das an als ob man sich an das althergebrachte klammern möchte. Wer hat sich den wirklich mal damit beschäftigt (Coden) über mehrere Wochen oder Monate? Wer hat sich mal ein Buch zu dem Thema gegönt?
Das Scala performanter als Java ist (Google Ausarbeitung) stört keinen. Das Martin Odersky selber mal ein Mitentwickler der Java VM war und weis wie der Hase läuft oder James Gosling Scala Befürworter ist und die EU mit 2.3 mio Euro Scala fördert ist wahrscheinlich alles kein Argument aber sollte das nicht mal Motivation geben sich mal länger auf das Thema einzulassen?
Falls du irgendwann auf die Idee kommts primitive Typen zu verallgemeinern, dann hast du einfach mißverstanden wo man die primitive Datentypen einsetzen soll und was deren Vorteil ist und warum sie nicht nur in Java unentbehrlich sind.
Warum ist es eine dumme Idee, einmal sowas zu schreiben...
Java:
public static number square(number n) {
return n*n;
}
...statt...
Java:
public static byte square(byte n) {
return n*n;
}
public static short square(short n) {
return n*n;
}
public static int square(int n) {
return n*n;
}
...
???
Wie das der Compiler intern umsetzt, ist doch eine ganze andere Frage (wie z.B. Scala sehr schön zeigt).
Ich finde es amüsant, wie man einerseits auf Scalas Schwachstellen herumhackt und sich andererseits Javas kapitale Böcke schönredet. Wie gesagt: Nichts gegen sachliche Scala-Kritik, aber dann muss auch Java auf den Prüfstand...
Ich arbeite mit Java, finde Scala interessant, habe damit aber noch nichts gemacht (außer mir mal ein Scala-Buch durchzulesen und so). Mir gefällt die Möglichkeit, so mehr oder weniger wie in Java zu programmieren, aber weniger Boilerplate-Code zu haben. Dadurch werden die Programme kürzer und lesbarer - ich würde (erstmal) keine abgefahrenen Sachen machen, vom Verständnis wäre es also wie in Java, aber mit weniger Müll drumrum. Mag nicht nach einer Riesensache klingen, aber fände ich schon praktisch. Mal ein Beispiel von mir auf Arbeit, Operationen mit Matritzen:
Java:
SimpleMatrix mS = mD.minus(mB.transpose().mult(mAi).mult(mB));
In Scala oder Sprachen mit Operator-Überladung wird das schon sehr viel lesbarer:
Java:
val mS = mD - (mB.tr * mAi * mB)
Dazu kommen Kleinigkeiten wie kein Schreiben (und Lesen) von Gettern nötig, kein doppeltes Angeben von Typen bei Deklaration + Definition nötig und hie und da mal die Übergabe von einer Funktion zum Sortieren, Filtern oder Umformen von Listen. Das alles erscheint mir erstmal recht praktisch. Aber wie in jeder Sprache kann man es natürlich auch übertreiben - in dieser vielleicht eher, als in anderen, weil man viele Möglichkeiten hat. Aber wenn ich mir manches C++ Programm anschaue... Letztlich hat der Programmierer natürlich eine gewisse Verantwortlichkeit. Ich denke aber auch, dass es in Java schwieriger ist, wirklich abartigen Code zu schreiben (die Möglichkeiten bei C++ oder Scala sind da einfach größer), so dass ich nicht glaube, dass Scala Java in jedem Fall ersetzen sollte.
PS: Ich arbeite selber im akademischen Umfeld (habe daher auch mehr mit mathematischem Zeugs und Algorithmen zu tun, so wie im Beispiel oben). Nichts desto trotz würde ich Scala (oder eine ähnliche Sprache) auch für Webanwendungen oder sowas einsetzen, einfach weil es Schreib- und Lesarbeit spart. Solang man es nicht mit abgefahrenen Konstrukten übertreibt...
Ich sehe im Moment auch die fehlende Generizität für primitive Datentypen als eine der größten Schwächen von Java (in bezug auf den echten "Sprachkern"). Wenn man sich die Redundanz in Arrays (Java Platform SE 6) anschaut, rollen sich einem die Fußnägel hoch. Und jeder, der schonmal in Erwägung gezogen hat, sich einen Codegenerator zu schreiben, um einen Satz von Methoden für alle primitiven Typen anzubieten, weiß, dass das ein Krampf ist :autsch:
Ich denke aber, dass die Lösung dafür NICHT (!) darin bestehen sollte, alle primitiven Typen zu Objekten zu erheben. An manchen Stellen braucht man 1 Million bytes als zusammenhängenden Speicherblock, und eben bitteschön nicht 1 Million 4 oder 8 byte große Referenzen, die ins Heap-Nirvana zeigen. Wie Landei ja auch gesagt hat: Da was dran zu machen ist Sache des Compilers. Ob und inwieweit das bei Java noch möglich sein wird, wird sich zeigen. Das Typsystem IST schon komplex, mit Autoboxing und Bounded Wildcards, ... Zumindest hat Brian Goetz mal angedeutet, dass primitive Typen sich vielleicht irgendwann besser dort einfügen, aber verbindliches oder konkretes gibt's dazu AFAIK nicht...
vielleicht verstehe Deinen Einwand nicht ganz, aber die 1700 Zeilen beziehen sich doch auf eine konkrete alternative rohe MPI Quicksort Implementierung. Imho ist der Vergleich so nicht fair. Würde man die 1700 MPI Zeilen in ein "void quicksort(final byte[] values)" "verstecken", wäre der Vergleich 10 Zeilen DSL vs. 1 Zeile Java. Egal wie später die Problemstellung für den Rechner formuliert wird, der Rechenaufwand ist dabei immer gleich. Und die Länge (in Codezeilen) der Aufgabenstellung (evtl. DSL) vermutlich umgekehrt proportional zu den möglichen Freiheitsgraden innerhalb der Problemstellung.
Der letzte Satz ist IMHO der entscheidende Punkt: Dass man beliebig komplexe Dinge im Stile einer Bibliothek hinter einem Methodenaufruf verstecken kann (z.B. eine ganze Anwendung hinter einem [c]main(null);[/c] ) bezweifelt ja niemand. Man könnte es grob so formulieren, dass der Unterschied darin liegt, wie mächtig/high-level die Strukturen sind, die tatsächlich der Compiler schluckt - und an denen er, im oben schon angedeuteten Sinn, noch etwas "drehen" kann. Wenn man in diesem NESL-Like Code als Pivotlement jetzt nicht ein zufälliges wählen will, sondern immer das mittlere, kann man das einfach machen....
Unabhängig davon halte ich den Vorteil, den funktionale Programmierung im Bezug auf Multi/Manycore Anwendungen haben soll, für überbewertet. Damit daraus ein Vorteil für den normalen Anwendungsentwickler entsteht, müssen imho einige Randbedingungen erfüllt sein:
...
Auf der anderen Seite stehen dann doch nur noch die GPU Fetischisten (z.B. mit OpenCL) oder die Leute die richtig rocken wollen (z.B. mit OpenMP / MPI). Das sind aber absolute Nischen, nichts was für die breite Masse der Entwickler von Interesse wäre.
Die Bedingungen sind klar, aber ich denke, dass es nicht unbedingt darum geht, dass wir alle in Zukunft nur noch funktional programmieren, sondern nicht zuletzt (oder sogar zuerst) darum, funktionale Aspekte in die alltägliche Programmierung einfließen zu lassen. Sowas wie
Java:
sineList = floatList.applyToAll(sineFunction);
ist das Paradebeispiel, das funktional ist, und in vielen Fällen "trivial parallelisierbar" - trotzdem will der high-Level Java-Programmierer sich dafür keinen OpenCL-Kernel schreiben, sondern er will es genau so schreiben, wie es dort steht. Ich habe es schon mehrfach betont, muss es aber nochmal: Die Anzahl der Kerne wird sich in Zukunft dramatisch erhöhen, und die Zeit des "free lunch", bei dem die Softwareleute immer komplexere Programme geschrieben haben und immer mehr Daten verarbeitet haben, und sich die Hardwareleute darum gekümmert haben, dass es schneller (oder zumindest nicht langsamer) läuft, ist endgültig vorbei. In Zukunft wird niemand mehr um Multi- oder sogar Manycore-Programmierung drumrumkommen, und das ist wirklich nicht trivial - ohne eine gute Unterstützung durch Sprachen und Compiler wird die Programmierung da einfach zu komplex. Ob Scala da die "Silver Bullet" darstellt oder nicht, oder inwieweit das durch Java-Erweiterungen unterstützt wird, weiß ich aber auch nicht...
wenn man in Java Number wie Integer oder selbstdefinierte Klassen haben möchte, kann man das doch machen?,
solange nicht die primitiven Datentypen mangels Verwendung von alleine aussterben gibt es absolut keinen Grund sie zu verbieten oder darauf rumzuhacken
... ist das Paradebeispiel, das funktional ist, und in vielen Fällen "trivial parallelisierbar" - trotzdem will der high-Level Java-Programmierer sich dafür keinen OpenCL-Kernel schreiben, sondern er will es genau so schreiben, wie es dort steht. Ich habe es schon mehrfach betont, muss es aber nochmal: Die Anzahl der Kerne wird sich in Zukunft dramatisch erhöhen, und die Zeit des "free lunch", bei dem die Softwareleute immer komplexere Programme geschrieben haben und immer mehr Daten verarbeitet haben, und sich die Hardwareleute darum gekümmert haben, dass es schneller (oder zumindest nicht langsamer) läuft, ist endgültig vorbei. In Zukunft wird niemand mehr um Multi- oder sogar Manycore-Programmierung drumrumkommen, und das ist wirklich nicht trivial - ohne eine gute Unterstützung durch Sprachen und Compiler wird die Programmierung da einfach zu komplex. Ob Scala da die "Silver Bullet" darstellt oder nicht, oder inwieweit das durch Java-Erweiterungen unterstützt wird, weiß ich aber auch nicht...
Sehe ich genauso. Scala's Killer-Technologie kann eigentlich nur parallele Programmierung sein, obs wird steht auf einem anderen Stern...
Java hat sich lange Zeit nicht weiter entwickelt, weil Sun einfach keine Mittel hatte, aber seitdem Oracle ja Sun aufgekauft hat, tut sich dahingehend doch einiges und mit Java 8 und Closures holt Java auch ein wenig auf, mal schauen, ob es erstmal genügt - Denn die "beste" Abstraktion zur parallelen Programmierung hat erst angefangen.
Die kann man aber dank fehlender Operatorüberladung nicht vernünftig einsetzen. Außerdem sind sie nicht effizient, da die JVM kleine Objekte nicht wegoptimiert. In Scala werden zumindest die primitiven JVM-Typen immer optimiert wenn möglich. Und dank spezialisierten parametrisierten Typen ist es auch möglich numerische Berechnungen ohne großen Overhead effizient zu implementieren.
Weiß ja nicht, was du unter Forschungssprachen verstehst. Ich würde das mit einem klaren "jein" beantworten...
Java wird auch in der Forschung eingesetzt und es gibt eine Menge wissenschaftlicher Veröffentlichungen dazu,
Wer kommt denn sonst auf die Idee unglaublich komplizierte Dinge auf einer höheren Ebene zu beschreiben.
Naja, die Welt ist leider nicht immer so einfach wie man es gerne hätte. Durchaus möglich, dass Scala nie eine wirklich große Verbreitung haben wird, aber es muss auch passende Werkzeuge für etwas anspruchsvollere Aufgaben (und Programmierer) geben. Wenn ich tonnenweise Java-Code schreiben muss um die Limitationen der Sprache zu umgehen ist das auch alles andere als "lesbar" und fehlerunanfällig.
Ich gehe mal davon aus, dass die Komplexität von Software in den nächsten Jahren eher zunehmen wird und ob man da mit eher "primitiven" Sprachen wie Java noch so weit kommt wird sich zeigen.
Jetzt bitte nicht falsch verstehen, mir geht es nur um die Industrietauglichkeit von Scala im Bereich Web, Mobile (Apps) usw das was halt zur Zeit gefragt ist.
Webanwendungen könnte eher eine Stärke von Scala werden, schau dir mal die Entwicklung vom Play-Framework an. In der nächsten Version kommt Unterstützung für bessere String-Interpolation. Da freue ich mich schon darauf
"Ich kann der Argumentation, dass der immer kürzer werdende Code lesbarer sein soll, nicht folgen. Man braucht immer mehr implizites Wissen, um zu verstehen, was da eigentlich passiert. Was der Entwickler dann ursprünglich wollte, war dann im Zweifel nochmal etwas komplett anderes."
Jetzt müsste man nur noch wissen, ob das von jemandem kommt, der Scala auch wirklich eingesetzt hat. Das war ja keine Voraussetzung für die Teilnahme.
Sonst sieht das doch schon eher positiv aus, würde ich sagen. Sogar positiver, als ich vorher erwartet hätte.
66% der Befragten sind in einer Softwarefirma oder IT-Abteilung, es haben sich also nicht nur reine Akademiker beteiligt
2% geben an, dass ihre Erfahrungen negativ waren, 61% positiv, 6% neutral und 31% setzen es nicht ein.
22% planen keinen Einsatz von Scala und 28% haben sich noch nicht entschieden. 11% wollen es sogar als hauptgenutzte Sprache einsetzen.
7% finden Scala zu kompliziert und 28% finden nur den Einstieg schwierig.
Das Beispiel ist einwenig praxisuntauglich...
Du weisst schon dass byte, short, int und long verschiedene Wertebereiche haben und solche zusammenfassung zu
Ja, sag das mal den Java-Entwicklern...
In Scala gibt es schon etwas, das diese Funktionalität bietet (natürlich nicht so extrem und umfangreich wie in C++).
Wir können auch gern Scala und C++ vergleichen, aber dann kann keiner mehr mit "Scala ist zu kompliziert" ankommen.
Mir ist klar was er damit aussagen wollte. ich weis zwar nicht was ein HPC Kurs ist aber ich denke den könnte man auch direkt bei dem Informatik Prof. nehmen Esser Friedrich
HPC ist die Abkürzung für High-performance computing. Normalerweise werden in den zugehörigen Vorlesungen / Kursen / Praktika nebenläufige Algorithmen und deren Vor- / Nachteile auf verschiedenen Plattformen behandelt. Bei uns hatte die entsprechende Vorlesung z.B. auch ein zugehöriges Praktikum, bei dem konkrete Beispiele in Java realisiert wurden. Behandelt wurde dabei ein Querschnitt von der einfachen Matrixmultiplikation auf dem 2 Kern Rechner bis zum Cluster mit mehreren Tausend Kernen.
Man darf das Zitierte nur überspitzt polemisch auffassen (sonnst wäre es traurig). Was an sich auch legitim wäre, würde er es anschließend wieder in den richtigen Kontext rücken. Aber so besteht die Gefahr das ein Leser, welcher nicht zufällig mal in dieses Themengebiet reinschnuppern durfte, diese Aussage unreflektiert übernimmt.
Die Bedingungen sind klar, aber ich denke, dass es nicht unbedingt darum geht, dass wir alle in Zukunft nur noch funktional programmieren, sondern nicht zuletzt (oder sogar zuerst) darum, funktionale Aspekte in die alltägliche Programmierung einfließen zu lassen. Sowas wie
Java:
sineList = floatList.applyToAll(sineFunction);
ist das Paradebeispiel, das funktional ist, und in vielen Fällen "trivial parallelisierbar" - trotzdem will der high-Level Java-Programmierer sich dafür keinen OpenCL-Kernel schreiben, sondern er will es genau so schreiben, wie es dort steht.
Das ist doch auch perfekt valide Java Syntax. Zur Deklaration von sineFunction ist zurzeit noch etwas boilerplate notwendig, eine Handvoll Zeilen in einer eingebundenen Bibliothek reichen zur Umsetzung.
Very quick and very dirty und unsinnige Spielerei:
Java:
public interface ParallelFunction<T extends Number> {
public T call(T value);
}
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@SuppressWarnings("serial")
public class ParallelArrayList<T extends Number> extends ArrayList<T> implements ParallelList<T> {
private static final int POOL_SIZE = 4;
private final ExecutorService pool = Executors.newFixedThreadPool(POOL_SIZE);
@Override
public List<T> applyToAll(final ParallelFunction<T> function) throws InterruptedException {
@SuppressWarnings("unchecked")
final T[] results = (T[]) Array.newInstance(get(0).getClass(), size());
final CountDownLatch latch = new CountDownLatch(size());
for (int i = 0; i < size(); i++) {
final int current = i;
pool.submit(new Callable<Object>() {
@Override
public T call() {
results[current] = function.call(get(current));
latch.countDown();
return null;
}
});
}
latch.await();
return Arrays.asList(results);
}
}
Java:
import static org.junit.Assert.assertEquals;
import java.util.List;
import java.util.Random;
import org.junit.Test;
public class TestParallelArrayList {
@Test
public void testApplyToAll() throws InterruptedException {
final int testSize = 2000000;
final Random random = new Random(0);
final ParallelFunction<Double> function = new ParallelFunction<Double>() {
@Override
public Double call(final Double value) {
return Math.sin(value);
}
};
final ParallelList<Double> list = new ParallelArrayList<Double>();
for (int i = 0; i < testSize; i++)
list.add(random.nextDouble());
// /////////////////////////////////////////////////////
final List<Double> sineList = list.applyToAll(function);
// /////////////////////////////////////////////////////
for (int i = 0; i < testSize; i++)
assertEquals(function.call(list.get(i)), sineList.get(i));
}
}
Das Problem, was ich eben sehe, ist das die aktuelle Rechnerarchitektur Grenzwerte festlegt, ab wann es sich lohnt ein Problem parallel zu lösen und wann es sich eben nicht lohnt. Das ist auch völlig unabhängig davon, wie viele Kerne verwendet werden. Sobald irgendwo eine Synchronisation notwendig wird (und eine ist immer notwendig (z.B. oben "latch" als Signal, das die Liste fertig ist) kommt es zu einem Overhead. Und solange dieser Overhead größer ist als das Problem, lohnt es sich nicht das Problem zu parallelisieren. Und das ist völlig Sprachunabhängig, sondern eine Limitierung durch die Hartware.
Ein konkretes Beispiel: Das Dekodieren eines Videostromes. Vereinfacht betrachtet bestehen viele komprimierte Videos aus einer Folge von Keyframes und "Folgeframes". Will man das Dekodieren parallelisieren, gibt es zwei Ansätze:
1.: Man versucht EIN Keyframe (und seine Folgeframes) mit Hilfe von N Threads zu dekodieren.
2.: Man verteilt N Keyframes (und seine Folgeframes) auf N Threads.
Funktionale Ansätze gehen von der Parallelisierung im Kleinen aus und versuchen jeden Schritt parallel auszuführen. Das führt dann zu Variante 1. Bei dieser Variante sind aber sehr viele Daten voneinander abhängig und es muss sehr viel synchronisiert werden. Der Overhead ist groß und das Verfahren skaliert bescheiden.
Der 2. Ansatz ist das, was ich oben mit trivial parallelisieren meinte. Dort ist praktisch keine relevante Synchronisierung notwendig und das Verfahren skaliert fast linear. Hat aber den Nachteil, dass ich als Entwickler hingehen muss und an einer ganz konkreten Stelle scheiben muss "mach genau DAS jetzt parallel".
Der Spoiler wäre nicht nötig gewesen, ich denke, die meisten können sich in etwa vorstellen, wie das aussehen könnte - so, und jetzt bau' das zu einer schönen, flexiblen Bibliothek aus! :bae:
Martin Odersky hat auch schon ein Paper dazu geschrieben, "A Generic Parallel Collection Framework" ( PDF: http://infoscience.epfl.ch/record/150220/files/pc.pdf ), es gibt auch das JSR zu ParallelArray und Dinge wie gpars (Groovy Parallel Systems) - Parallelizer - es wird intensiv daran gearbeitet. Aber die entscheidenden Punkte zu dem Java-Snippet hast du schon angedeutet:
1. Häßlicher Boilerplate code (dürfte mit Java 8 und SAM-Types schon deutlich besser werden!)
2. Abhängigkeit von der Zielarchitektur
Und gerade das zweite kann ja eigentlich nur elegant versteckt und behandelt werden, wenn man den Code, den du gepostet hast, eben nicht selbst per Hand hinschreiben muss, sondern das (oder etwas anderes, ggf. zur Laufzeit an die Architektur angepasstes) dem Compiler überläßt.
Das kleine Aufgaben schlecht zu parallelisieren sind hat ja niemand bezweifel.
Das mit der Schwangerschaft hast du falsch dargestellt.
Wenn du zwei unterschiedliche Frauen (Cores) zur selben zeit schwängerst dann hast du nach 9 Monaten auch das doppelte an Leistung
Zu Oracle:
Soviel wir alle wissen planen sie auch eine Enterprise VM. Es ist durchaus möglich das sie da eine bessere Nebenläufigkeit implementieren aber darauf wetten würde ich nicht. Wie gut der Java VM die kostenpflichtig Abspaltung tut ist eine andere frage.
Und bei Scala kann ich mich des Eindrucks nicht erwähren, dass dabei besonders gerne abgefahrene Syntaxspielchen eingesetzt werden. Ich meine ein
Code:
#pragma omp parallel for
for (i = 0; i < N; i++)
a[i] = 2 * i;
gibt es jetzt seit bald 15 Jahren. Das ist zwar natürlich nicht so mächtig wie eine abgefahrene mit Scala umgesetzte DSL. Der Vorteil ist jedoch, dass es praktisch von jedem Schüler gelesen werden kann, welcher irgendwann und irgendwo schon mal irgendein Programm gelesen hat.
Das ist eigentlich keine abgefahrene DSL, oder? 3 Methoden aus der Standardbibliothek und eine anoyme Funktion, mehr ist es ja nicht.
Falsch machen kann man dabei nicht viel im Vergleich zu Schleife und das sollte auch von jedem halbwegs intelligentem Menschen verstanden werden, spätestens nach 30 Sekunden Erklärung
Finde ich eher traurig, wenn man solche Konstrukte als Programmierer noch nie gesehen hat und nur in Schleifen denken kann. Ich kann das nicht besonders gut, daher nehme ich lieber was anderes, bei dem man nicht so viele Fehler machen kann...
Aber erst wenn es das nächste Mal wieder nachmittags regnet.
Nein, ernsthaft hätte ich damit wohl ein richtiges Problem, weil ich nicht glaube, dass die Parallelisierung "aus dem Kleinen heraus" so sonderlich effizient wäre (neben der Zeit zur Umsetzung und so ).
Und beim Versuch die Parallelisierung "aus dem Großen heraus" zu abstrahieren würde ich wohl vermutlich bei einer zum Callable ähnlichen Variante landen. Beides halte ich aber langfristig nicht für das Optimum.
Und gerade das zweite kann ja eigentlich nur elegant versteckt und behandelt werden, wenn man den Code, den du gepostet hast, eben nicht selbst per Hand hinschreiben muss, sondern das (oder etwas anderes, ggf. zur Laufzeit an die Architektur angepasstes) dem Compiler überläßt.
Imho ist das der einzig gangbare Weg. Eine Datenflussanalyse und Komplexitätsabschätzung auf dem AST bzw. Zwischencode während des Kompilierens könnte die Bereiche sichtbar machen, die sich sinnvoll auf verschiedene Kerne verteilen lassen. Und das ist imho auch genau das an dem die Compilerbauer gerade basteln. Wenn man das so realisiert, ist das aber unabhängig der Quellsprache und damit kein Vorteil der funktionalen Programmierung mehr.
Das mit der Schwangerschaft hast du falsch dargestellt.
Wenn du zwei unterschiedliche Frauen (Cores) zur selben zeit schwängerst dann hast du nach 9 Monaten auch das doppelte an Leistung
Dann ist es aber kein paralleler Algorithmus mehr, sondern nur das parallele Ausführen zweier voneinander unabhängiger sequenzieller Algorithmen. Das ist dann das was ich oben mit trivial parallelisierbar umschrieben habe. Das ist einfach und skaliert gut. Das Gegenteil wäre eben wenn Du versuchst EINE Schwangerschaft auf 4 1/2 Monate zu drücken, das skaliert nicht und funktioniert auch nicht wirklich.
Das ist eigentlich keine abgefahrene DSL, oder? 3 Methoden aus der Standardbibliothek und eine anoyme Funktion, mehr ist es ja nicht.
Falsch machen kann man dabei nicht viel im Vergleich zu Schleife und das sollte auch von jedem halbwegs intelligentem Menschen verstanden werden, spätestens nach 30 Sekunden Erklärung
Ja, so ist das noch einfach. Es lässt sich aber leider auch nicht ganz vergleichen. Mein obriger Abschnitt bezog sich auf ein Beispiel zu OpenMP. Ganz abstract und vereinfacht gesehen, ist der Ansatz dabei, dass man eigentlich ein sequenzielles Programm schreiben könnte, bei dem man über die OpenMP Direktiven dem OpenMP Preprozessor eben sagen kann: "Mach genau DAS JETZT parallel (und nur DAS!)".
Wenn man Deine Variante umsetzt, stellt sich intern die frage, soll das auf einem Kern oder auf vielen durchgeführt werden? Im Hinblick auf funktionale Manycore-Programmierung führt das dann dazu das alles was möglich ist parallelisiert wird ("Parallelisierung aus dem Kleinen heraus"). Das wiederum führt aber dazu das eigentlich unnötiger Overhead produziert wird, weil das Problem (möglicherweise) auch trivial zu parallelisieren gewesen wäre (und dann ohne Overhead). (Wie in dem Beispiel zum Videodekodieren)
Vielleicht noch als Nachtrag für die, die OpenMP nicht kennen. Man kann die OpenMP Direktiven nicht nur auf Schleifen anwenden ("Parallelisierung im Kleinen"), sondern eben z.B. auch auf Blöcke (was dann ehr "Parallelisierung im Großen" entspricht).
Ja, so ist das noch einfach. Es lässt sich aber leider auch nicht ganz vergleichen. Mein obriger Abschnitt bezog sich auf ein Beispiel zu OpenMP. Ganz abstract und vereinfacht gesehen, ist der Ansatz dabei, dass man eigentlich ein sequenzielles Programm schreiben könnte, bei dem man über die OpenMP Direktiven dem OpenMP Preprozessor eben sagen kann: "Mach genau DAS JETZT parallel (und nur DAS!)".
Das mit OpenMP ist mir schon klar, ich sehe nur den Unterschied nicht so wirklich. In meinem Fall habe ich doch auch gesagt, dass genauso diese Operation parallel ausgeführt werden soll. Das ist ja auch nichts Anderes als eine parallelisierte Schleife.
Dann ist es aber kein paralleler Algorithmus mehr, sondern nur das parallele Ausführen zweier voneinander unabhängiger sequenzieller Algorithmen. Das ist dann das was ich oben mit trivial parallelisierbar umschrieben habe. Das ist einfach und skaliert gut. Das Gegenteil wäre eben wenn Du versuchst EINE Schwangerschaft auf 4 1/2 Monate zu drücken, das skaliert nicht und funktioniert auch nicht wirklich.
Ja schon klar Mein Beispiel war dem Raytracing Problem geschuldet und da hast du viele Möglichkeiten wo du wunderbar funktional und parallel arbeiten kannst.
Dann ist es aber kein paralleler Algorithmus mehr, sondern nur das parallele Ausführen zweier voneinander unabhängiger sequenzieller Algorithmen. Das ist dann das was ich oben mit trivial parallelisierbar umschrieben habe. Das ist einfach und skaliert gut. Das Gegenteil wäre eben wenn Du versuchst EINE Schwangerschaft auf 4 1/2 Monate zu drücken, das skaliert nicht und funktioniert auch nicht wirklich.
Wie das ist kein paralleler Algorithmus? Das nennt sich Datenparallelität, Beispiel GPU: Man partitioniert die Daten (also die Anzahl der Frauen im Harem) und führt die Operation "Bumsen" auf allen Frauen im Harem aus. Das ist dann eine SIMD-Operation (Single Instruction Multiple Data). Ein sequentieller Programmfluss auf einer Menge von unabhängigen leichtgewichtigen Threads (CUDA Terminologie für dünne Frauen) oder in OpenCL Terminologie: work-item (wobei man mit obiger Operation nicht unbedingt Arbeit verbindet). Jeder sequentielle Programmfluss kann miteinander kommunizieren, dass wäre dann das "Rudelbumsen". Der sequentielle Programmfluss dauert 9 Monate und bringt je in Abhängigkeit der if-Verzweigungen pro Thread entweder ein Kind zur Welt oder nicht. Des Kind kann man dann zurück an den Host (Vater) zurückgeben, der hat die Operation auch initiiert. Das Zurückgeben ist in der Regel aber nicht ganz billig (GPU - Host Interaktion kostet). Das nennt sich auch Stream-Bumsen, ähm, Computing, sorry.
Das was du meinst ist Task-Parallelität ist aber nur eine Form der Parallelität. In Bezug auf Task-Parallelität lässt sich das wirklich nicht partitionieren, denn eine Schwangerschaft dauert nun mal 9 Monate, und in diesem Modell ist der längste Ausführungsstrang entscheidend (falls man nur eine Menge an gleichzeitig startenden Programmsträngen betrachtet).
So einfach ist das nicht: Du kannst nicht einfach den Compiler anweisen, dass er "automatisch" parallelisieren soll. Wenn du das schaffst, dann bekommst du mit Sicherheit dern Touring-Award...
Ja, so ist das noch einfach. Es lässt sich aber leider auch nicht ganz vergleichen. Mein obriger Abschnitt bezog sich auf ein Beispiel zu OpenMP. Ganz abstract und vereinfacht gesehen, ist der Ansatz dabei, dass man eigentlich ein sequenzielles Programm schreiben könnte, bei dem man über die OpenMP Direktiven dem OpenMP Preprozessor eben sagen kann: "Mach genau DAS JETZT parallel (und nur DAS!)".
Was ist mit der Scheduling-Strategie? Das ist ein ganz integraler Bestandteil der OpenMP Direktiven. Da fangen die ganz großen Unterschiede an. Man kann das überhaupt nicht miteinander vergleichen...
Du machst es dir ziemlich einfach...
Wenn man Deine Variante umsetzt, stellt sich intern die frage, soll das auf einem Kern oder auf vielen durchgeführt werden? Im Hinblick auf funktionale Manycore-Programmierung führt das dann dazu das alles was möglich ist parallelisiert wird ("Parallelisierung aus dem Kleinen heraus"). Das wiederum führt aber dazu das eigentlich unnötiger Overhead produziert wird, weil das Problem (möglicherweise) auch trivial zu parallelisieren gewesen wäre (und dann ohne Overhead). (Wie in dem Beispiel zum Videodekodieren)
Als ob du bei OpenMP bestimmen könntest, auf welchen !Kern! die Ausführung stattfindet. Du vergleichst Äpfel aber sowas von mit Birnen... Du vertauscht Datenparallelität mit Taskparallelität. Wenn ich eine Parallele Schleife habe, dann habe ich Iterationen, deren Daten man partitionieren kann. Das was du ansprichst, würde man weder in OpenMP noch in Scala wie oben schreiben...
Parallelität ist so ein breites Feld, das könnt ihr nicht einfach mit einer parallelen Schleife abtun...
...Eine Datenflussanalyse und Komplexitätsabschätzung auf dem AST... Wenn man das so realisiert, ist das aber unabhängig der Quellsprache und damit kein Vorteil der funktionalen Programmierung mehr.
Ach so - ja, ich meinte das nicht speziell in bezug auf funktionales Programmieren sondern allgemein. Aber die Vorteile (speziell Zustandslosigkeit) der funktionalen Programmierung könnte da einiges (und zwar SEHR) deutlich leichter machen. Das, woran die Compilerbauer da meines Wissens am meisten knabbern sind ja gerade die Abhängigkeiten: Wer liest welche Variable wann, und wo zu Hölle zeigt dieser Pointer gerade hin? :autsch:
Zudem fand ich das Konzept des "nested parallelism", das Blelloch mit NESL beschrieben hat, sehr interessant. Damit könnte vielleicht auch die Trennung zwischen dem "aus dem Großen" und "aus dem Kleinen", die du angesprochen hast, angegangen werden. Richtig fundiert-konkret ist das in meinem Kopf gerade noch nicht, aber etwas plakativ gesagt geht es ja auch um die Frage, ab welchem Punkt man vom Groben, (meistens Task-Parallelen) zum Kleinen (oft Daten-Parallelen) wechselt...
Die Frage mit den 9 vs. 4 1/2 Monaten erinnerte mich jetzt ein bißchen an
Amdahl: Weniger Zeit bei gleicher Eingabegröße vs.
Gustafson: Mehr Daten ("höherer Durchsatz") bei gleicher Zeit
Letzteres hat den schönen Vorteil, nicht durch sequentielle Teile beschränkt zu sein...
Das mit OpenMP ist mir schon klar, ich sehe nur den Unterschied nicht so wirklich. In meinem Fall habe ich doch auch gesagt, dass genauso diese Operation parallel ausgeführt werden soll. Das ist ja auch nichts Anderes als eine parallelisierte Schleife.
Ja genau, wenn man das so fix hinschreibt, ist das Primär eine fixe parallele Schleife. Das Problem dabei ist das dieses harmlos scheinende [c](1 to n).par.map(_ * 2)[/c] dazu führt das alle Kerne für ein Problem belegt werden, bei dem von einer nicht sonderlich effizienten Gesamtlösung auszugehen ist. Ein Algorithmus, der das Problem als Ganzes betrachtet, könnte mit Sicherheit Effizienter arbeiten, er würde aber durch solche vermeintlichen Optimierungen behindert.
Bei OpenMP hast Du die Möglichkeit da viel feingranularer einzugreifen. Statt einem [c]#pragma omp parallel for[/c] schreibst Du halt z.B. ein [c]#pragma omp for schedule(guided)[/c]. (Das ist der Punkt auf den Gregorrr bereits hingewiesen hat.)
Ganz bewusst sogar! Außerdem ist das doch genau der Punkt, auf den ich die ganze Zeit hinauswill und bei dem ich in diesen Thread eingestiegen bin, nämlich inwieweit funktionale Ansätze bei der Multi-/Manycore - Programmierung förderlich sind:
Unabhängig davon halte ich den Vorteil, den funktionale Programmierung im Bezug auf Multi/Manycore Anwendungen haben soll, für überbewertet. Damit daraus ein Vorteil für den normalen Anwendungsentwickler entsteht, müssen imho einige Randbedingungen erfüllt sein: Das Problem sollte
- überhaupt parallelisierbar sein
- eine kritische Problemgröße aufweisen (zu groß für singe core, klein genug für SMP)
- nicht trivial parallelisierbar sein (sonst gibt es effizientere Ansätze)
- nicht sowieso ständig auf IO warten (Benutzer, Daten, ..)
Also zumindest mir fällt da nicht sonderlich viel ein. [...]
Einfach "Funktional = gut für Parallelität" ist dann nämlich wirklich zu einfach gemacht. Und schlimmstenfalls kann ein einfaches [c](1 to n).par.map(_ * 2)[/c] irgendwo versteckt auch eine optimierte Lösung hinrichten.
Ach so - ja, ich meinte das nicht speziell in bezug auf funktionales Programmieren sondern allgemein. Aber die Vorteile (speziell Zustandslosigkeit) der funktionalen Programmierung könnte da einiges (und zwar SEHR) deutlich leichter machen. Das, woran die Compilerbauer da meines Wissens am meisten knabbern sind ja gerade die Abhängigkeiten: Wer liest welche Variable wann, und wo zu Hölle zeigt dieser Pointer gerade hin? :autsch:
Genau, bei den Möglichkeiten der Compileroptimierung hat reine funktionale Programmierung Vorteile. Den Vorteil erkauft man sich aber entweder über komplizierte Datenstrukturen, die eben doch nicht richtig immutable sind, oder durch blankes Byteschupsen in gigantischem Umfang (Da ging es in Deinem verlinkten Thread ja hauptsächlich drum )
Zudem fand ich das Konzept des "nested parallelism", das Blelloch mit NESL beschrieben hat, sehr interessant. Damit könnte vielleicht auch die Trennung zwischen dem "aus dem Großen" und "aus dem Kleinen", die du angesprochen hast, angegangen werden. Richtig fundiert-konkret ist das in meinem Kopf gerade noch nicht, aber etwas plakativ gesagt geht es ja auch um die Frage, ab welchem Punkt man vom Groben, (meistens Task-Parallelen) zum Kleinen (oft Daten-Parallelen) wechselt...
Ja genau. Das Problem ist, das beide Seiten nicht nur Einfluss auf das Gesamtlaufzeitverhalten haben, sondern auch das Laufzeitverhalten der anderen Seite beeinflussen können. Ein System das (zumindest unterstützend hilft) das automatisch zu lösen, dürfte nicht ganz trivial werden.
(Und der Compilerbau ist der einzige Ansatzpunkt, den ich dafür überhaupt sehe.)
Die Frage mit den 9 vs. 4 1/2 Monaten erinnerte mich jetzt ein bißchen an
Amdahl: Weniger Zeit bei gleicher Eingabegröße vs.
Gustafson: Mehr Daten ("höherer Durchsatz") bei gleicher Zeit
Letzteres hat den schönen Vorteil, nicht durch sequentielle Teile beschränkt zu sein...
Wenn ich z.B. etwas in einer Menge suche und die Suche abgebrochen werden kann, sobald einer der Tasks etwas gefunden hat, ist eine parallele Schleife nur die halbe Miete.
Landei hat recht. Egal in welcher Sprache Automatismus aus einer Schleife heraus kann nur wenig oder nichts bringen wegen den bereits geposteten dingen wie... Seiteneffekte, Aufgabe zu schnell erledigt und vor allem kann immer nur ein Core einen Speicherbereich abarbeiten. Wenn Aufgaben parallel effektiv abgearbeitet werden sollen geht das sicher nur funktional und mit individuellen Threads welche die Arbeit ordentlich aufteilen.
Sollte es mal einen Zauber Compiler geben der das automatisch generiert dann wäre ich mehr als erstaunt.
Und, um mal wieder grob zu Scala zurückzukommen: Ich denke eben, dass nur mit "high level building blocks" ein Großteil dieser Arbeit auf den Compiler abgewälzt werden kann. Wenn man in C oder Java hinschreibt
Java:
int sum = 0;
for (int i=0; i<10; i++)
{
sum += array[i];
}
dann wird das direkt übersetzt - man kann sich praktisch 1:1 den Assembler- bzw. Bytecode dafür zusammenfrickeln. Da kann man nichts dran drehen, und insbesondere: Man kann dort nichts parallelisieren! Selbst mit [c]parallel for[/c] von OpenMP würde dort nichts gehen. Das, was dort gemacht wird, ist einfach nicht parallelisierbar.
Oder?
DOCH! Das ist ein Scan/Reduction, und einer der wichtigsten Bausteine für viele parallele Programme! Aber das kann eben praktisch* nur erkannt und vom Compiler ausgenutzt werden, wenn dort nicht diese for-Schleife steht, sondern ein ganz abstraktes
[c]var sum = array.reduce();[/c]
oder so...
* praktisch, weil es theoretisch durch Codeanalyse erkannt werden könnte, aber dafür bräuchte man dann den angedeuteten "Zaubercompiler"...
Wenn ich z.B. etwas in einer Menge suche und die Suche abgebrochen werden kann, sobald einer der Tasks etwas gefunden hat, ist eine parallele Schleife nur die halbe Miete.
Natürlich. Imho gibt es zwei Herangehensweisen ein Problem zu parallelisieren:
1. Man sucht kleine Einheiten heraus (z.B. eine Schleife) parallelisiert diese, kreuzt die Finger und hofft das es schneller geworden ist. (Das ist AUCH das, was ich immer wieder mit "parallelisieren aus dem Kleinen" heraus meine (und trifft in der Tat meistens die Daten-Parallelen Teile zuerst)
2. Man vergisst alles was man über die bisherige Problemlösung weiß, zieht sich in sein dunkles Kämmerlein zurück und betrachtet das Problem als großes Ganzes. (Das ist AUCH das, was ich mit "parallelisieren aus dem Großen" meine (und trifft eben meistens die Task-Parallelen Teile zuerst)
Meiner Erfahrung nach bringt Variante 2 die wesentlich besseren Ergebnisse. Funktionale Programmierung verleitet jedoch oft zu Variante 1. (Variante 1 kann das Laufzeitverhalten von Variante 2 negativ beeinflussen!)
Sieh Dir z.B. mal den Intel Parallel Advisor an. Insbesondere auch das Overview Viedeo. Das Ding ist aufgebaut wie ein Wizard und führt Dich in mehreren Schritten von einem sequenziellen Programm zu einem parallelen. Die Ergebnisse sind dabei wohl beachtlich (auch wenn ein Profi im dunklen Kämmerlein immer noch bessere Lösungen finden kann). Das Teil ist auch keine Zukunftsmusik, sondern ganz regulär im Handel erhältlich. (und funktioniert auch ganz ohne funktionale Programmierung der Quellsprache )
Ohne dem Rest widersprechen zu wollen und von der Vermutung ausgehend das Du das eh bereits weißt (imho war das): [c]#pragma omp parallel for reduction(+:sum)[/c]
Das Intel Video sieht für mich wie eine GUI aus womit ich Threads zusammenfassen kann?! Nicht mehr nicht weniger. Wenn man es böse ausdrücken will ist es nur eine Krücke. Ich denke aber das sich Funktionen mit festen Zuständen und oder immutable Daten immer NOCH erheblich besser parallelisieren lassen werden. Interessante ist das Video alle mal.
Deine zweite variante ist das wovon ich eigentlich spreche (und die anderen auch). Das Problem als ganzes sehen!
Sowas wird kein Compiler der Welt hinbekommen. Vielleicht in weiter Zukunft mittels KI ;-)
"Programmabschnitte" ohne Seiteneffekte lassen sich sehr gut parallelisieren.
FP mittels Rekursion, finalen Variablen und Immutablen Funktionen ist im vergleich zu OOP "merkwürdig" aber auch interessant,elegant und hat als süssen Beigeschmack das man kaum oder keine Seiteneffekte hat.
Ohne dem Rest widersprechen zu wollen und von der Vermutung ausgehend das Du das eh bereits weißt (imho war das): [c]#pragma omp parallel for reduction(+:sum)[/c]
Wußte ich nicht Zugegeben: Ich habe mich mit OpenMP noch nicht so intensiv beschäftigt, wie ich sollte. Das sollte in erster Linie ein Beispiel sein, für etwas, wo für das Parallelisieren nicht das "feingranulare" Wissen relevant ist ("Das ist eine for-Schleife") sondern das "grobgranulare" ("Das ist eine reduction"). Vermutlich wurde dieses 'reduction' wegen seiner besonderen Bedeutung für parallele Programme eingeführt - es gibt sicher ähnliche Beispiele, die nicht so direkt unterstützt werden.
Und außerdem.. sieht dieses OpenMP-Konstrukt im Vergleich zu einem
[c]list.foldLeft(0)(add)[/c]
in Scala dann SO komplizert aus, wie das Scala-Quicksort im Vergleich zu einem Collections.sort
Das Intel Video sieht für mich wie eine GUI aus womit ich Threads zusammenfassen kann?! Nicht mehr nicht weniger. Wenn man es böse ausdrücken will ist es nur eine Krücke.
Nein. Das Tool ist in der Lage das parallele Laufzeitverhalten eines sequenziellen Programms zu simulieren! Und es kann Vorschläge machen, welche Quellcodestellen eine effiziente Parallelisierung versprechen sowie dabei helfen, die zugehörigen Daten- und Laufzeit- Synkonisationspunkte zu bestimmen.
So einfach ist das in der realen Welt dann aber nicht. Such z.B. mal nach "structural sharing", nur weil etwas immutable aussieht, ist es noch lange nicht so trivial, wie es den Anschein hat. Da sind zum Teil sehr ausgeklügelte Algorithmen im Einsatz. Landei kann Dir da aber bestimmt kompetentere Auskunft geben.
Mal ein wenig mit OpenMP zu "spielen" kann ich nur empfehlen (wir haben damals imho JOMP genutzt (glaube das war noch 0.1 damals ). Da die OpenMP Direktiven nur so "locker" in den Quelltext eingestreut werden, hat man die Möglichkeit auch schnell mal verschiedene Varianten eines größeren Problems zu vergleichen. Dabei fällt dann auch auf, das "einfach alles parallel machen" (bei praxisrelevanten Problemen) fürchterlich ineffizient werden kann. (= bei Problemen, die eben nicht "nur" aus Quicksort bestehen, sondern z.B. die Berechnung der Flugbahnen von Satelliten)
Und außerdem.. sieht dieses OpenMP-Konstrukt im Vergleich zu einem [c]list.foldLeft(0)(add)[/c] in Scala dann SO komplizert aus, wie das Scala-Quicksort im Vergleich zu einem Collections.sort
Das Problem, was ich dabei sehe, ist das [c]list.foldLeft(0)(add)[/c] alleine wieder fest parallel verdrahtet wäre. Das ist aber eben nicht immer schneller, sondern hängt vom Gesamtkontext ab. Man müsste das dann entweder aufblassen zu einem z.B. [c]list.schedule(dynamic, 15).foldLeft(0)(add)[/c] (OpenMP Style) oder ein (verstecktes) komplexes Runtime-/Build- Ressourcenmanagement entwickeln, welches diese Einstellungen automatisch vornehmen kann (was nicht einfach werden könne ).
Ja, JOMP "kenne" ich, d.h. habe es mal gesehen, aber noch nicht direkt verwendet. Ich "kannte" früher auch schon Boost your Java application performance - Ateji PX for Java - Ateji , bin aber erst neulich nochmal drüber gestolpert, und habe da erst gemerkt, dass das ziemlich cool zu sein scheint, habe aber auch noch nicht genug damit gemacht ... und mit Groovy GPars, und java-gpu, und und und und... *schwitz*
Ateji sieht erstmal interessant aus. Interessant ist auch:
With Ateji PX, a source code written in message-passing style will also run without modifications on computer clusters, MPI-based supercomputers, across a network, and in the Cloud. A distributed version of Ateji PX is in preparation, where parallel branches can be run at remote locations. Watch Java Parallel Programming, Portfolio Optimization Software & Java Threads Made Simple - Ateji PX for announcements.
Message-passing at the language level also enables a simple expression of a wide range of parallel programming paradigms, including data-flow, stream programming, the Actor model, and the MapReduce algorithm.
Leider ist Ateji PX erstmal pleite gegangen Ateji is closed | The Dress of Thought Aber das Plugin für Eclipse 3.6 funktioniert anscheinend noch, und die Verantwortlichen suchen natürlich nach einer Lösung wie es da weitergehen kann...
Nun gut das zur Parallelität
Ups... noch ein kleine Ergänzung.Die Spielindustrie hat jahrelang an der MultiCore Auslastung gearbeitet. Ich denke gute Parallelität läßt sich weder mit Zauber-Compilern noch mit Tools realisieren und funktioniert sicherlich am besten mittels Designe im Quellcode.
Abschliessend kann man noch sagen das man vor Scala keine angst haben braucht. Wer sich mittels Scala ins Knie schießen will kann das sicherlich tun, wer seine Kollegen "ärgern" will mit unlesbaren Sourcecode der kann das sicher auch machen. Man sollte dabei aber auch die ganzen vorteile nicht vergessen. Wer hat gesagt man MUSS alles via FP lösen? Wer hat gesagt man MUSS kryptischen Code schreiben ? Gibt den krams eine Chance und ihr werdet merken das es eigentlich keine nachteile sondern nur vorteile in Scala gegenüber Java gibt. Scala ist wie die "Macht" aus StarWars. Man kann viel gutes damit tun aber auch viel schlechtes
Nun gut das zur Parallelität
Man sollte dabei aber auch die ganzen vorteile nicht vergessen. Wer hat gesagt man MUSS alles via FP lösen? Wer hat gesagt man MUSS kryptischen Code schreiben ? Gibt den krams eine Chance und ihr werdet merken das es eigentlich keine nachteile sondern nur vorteile in Scala gegenüber Java gibt. Scala ist wie die "Macht" aus StarWars. Man kann viel gutes damit tun aber auch viel schlechtes
die letzten Seiten nicht gelesen,
aber einfach um mal wieder irgendwas reinzuschießen:
nach der Begründung könnte man auch zu C++ oder was auch immer mit Pointern direkt im Speicher zurückgehen,
muss man ja nicht verwenden..