Ist das Funktionsparadigma bei der zugrunde liegenden Hardware nicht zu unterschiedlich, um generell effizient zu sein?


14

Inspiriert von einer Frage von SO: /programming/6623391/how-to-gain-control-of-a-5gb-heap-in-haskell

Es kann eine lange Debatte über die zahlreichen Vor- und Nachteile von FP sein, aber im Moment möchte ich den Anwendungsbereich auf die Haupteffizienz von FP für moderne Hardware beschränken.

These:

Das Funktionsparadigma impliziert Unveränderlichkeit und Zustandslosigkeit (?), Aber die Hardware, auf der wir Funktionsprogramme ausführen, sind zustandsbehaftete endliche Automaten. Die Übersetzung von 'rein funktionalem' Programm in eine 'zustandsbehaftete Hardware'-Darstellung überlässt dem Programmierer wenig Kontrolle, bringt Overhead (?) Und schränkt die Verwendung von Hardware-Funktionen (?) Ein.

Habe ich in den fraglichen Aussagen Recht oder Unrecht?

Kann nachgewiesen werden, dass FP für die moderne Allzweck-Computerarchitektur wesentliche Leistungseinbußen mit sich bringt / nicht mit sich?

EDIT: Wie ich bereits zu einigen Kommentaren ausgeführt habe, geht es bei der Frage nicht um die Implementierungsleistung und Details. Es geht um das Vorhandensein oder Nichtvorhandensein von Hauptaufwand , den das Ausführen von FP auf statusbehafteten Automaten mit sich bringen kann.


3
Haben Sie sich jemals wirklich angesehen, wie moderne Hardware auf niedrigem Niveau funktioniert? Wenn Ihnen die Effizienz am Herzen liegt, ähnelt sie auch nicht der alltäglichen imperativen Programmierung.
CA McCann

Ob Sie es glauben oder nicht, aber die Informatiker, die funktionale Programmiersprachen und Compiler entwickelt haben, wissen auch ein wenig über die Optimierung der Leistung. Das ist nicht das Ziel eines jeden funktionalen Sprachprodukts, sondern für die seriösen Produktionsplattformen.
Jeremy

@camccann, @Jeremy: C # und Java verwenden beispielsweise virtuelle Maschinen. Egal wie optimal es ist, egal wie effizient C # - und Java-Programme für die Produktion sind, es gibt eine Hauptursache für Ineffizienz, und es ist die VM. Die Frage ist nicht über die Implementierungsleistung, sondern running FP on stateful automata.
Reben


2
@vines: Sie erkennen, dass moderne VMs mit ausgefallenem JITing in einigen Fällen sogar den nativen Code übertreffen können, oder? Und dass der gesamte Zweck eines Compilers darin besteht, ein Programm in eine Darstellung zu konvertieren, die der zugrunde liegenden Architektur entspricht, die sich von jeder modernen Sprache unterscheidet? Ihre Frage ergibt keinen Sinn.
CA McCann

Antworten:


7

Unveränderlichkeit ist ein großes Missverständnis.

Die Unveränderlichkeit ist ein Merkmal der Semantik, impliziert jedoch keine Unveränderlichkeit bei der Implementierung.

Ein einfaches Beispiel ist die Implementierung von Faulheit.

Wenn Berechnungen verzögert sind, ist das Ergebnis eines Ausdrucks konzeptionell ein Wert, aber die zugrunde liegende Implementierung ist ein Thunk, der die auszuwertenden Argumente und eine Funktion zum Erstellen des Werts sowie einen Steckplatz zum Speichern des Werts enthält.

Wenn Sie zum ersten Mal (in der Sprache) nach dem Wert fragen, wird die Berechnung tatsächlich durchgeführt, das Ergebnis ausgewertet und der Wert an Sie zurückgegeben (oder ein Handle).

Dies ist in der Sprachsemantik transparent, und Sie wissen nur, dass diese Variable an einen Wert (oder einen zukünftigen Wert) gebunden wurde und dass Sie den zurückgegebenen Wert danach nicht mehr ändern können. Die zugrunde liegende Speicherdarstellung ändert sich, aber Sie wissen nichts davon.

Der gleiche Unterschied zwischen Semantik und Implementierung besteht in nahezu jeder Sprache und steht im Mittelpunkt der Optimierung . Unabhängig von der Sprache garantiert die Semantik einige Dinge, während andere nicht spezifiziert sind, um Optimierungsspielraum zu lassen.

Nun ist es wahr, dass praktisch funktionale Sprachen nicht so schnell sind wie beispielsweise C ++. Allerdings Go(was immer noch ein ziemlicher Hype ist) ist langsamer als Haskell oder Lisp, ebenso wie C # Mono ( Quelle ).

Wenn Sie sehen, wie unzuverlässig C ++ oder C sein kann, um diese Leistungen zu erzielen, möchten Sie vielleicht ein wenig loslassen.

Wenn Sie feststellen, dass Haskell heute schnell wächst und noch viel Optimierungsspielraum für den Compiler / die Laufzeit besteht (GHC hat kürzlich auf LLVM umgestellt, z. B. finanziert Microsoft Research die Laufzeitverbesserungen aktiv), sind Sie möglicherweise bereit, darauf zu wetten es wird sich bald verbessern.

Spaß: Ein Spiel mit regulären Ausdrücken oder wie ein Haskell-Team einen Matcher für reguläre Ausdrücke erstellt hat re2, der in einer Reihe von Szenarien die C-Bibliothek von Google übertrifft .


Klingt optimistisch :)
Reben

3

Funktionsparadigma ist nützlich, um Dinge in einem engen Rahmen aufzuteilen. Dies ist eine wirklich gute Sache, wenn man bedenkt, wie sich der Computer entwickelt.

Multicore-CPUs haben große Probleme beim Umgang mit gemeinsam genutzten Ressourcen, und die Synchronisationskosten sind sehr hoch. Das Funktionsparadigma ermöglicht es auf natürliche Weise, Programme auszudrücken, die diese Probleme nicht haben. Das ist wirklich gut für die Parallelität.

Darüber hinaus verwenden wir zunehmend Serverfarmen mit SaaS und Cloud Computing. Daher muss dieselbe Anwendung auf mehreren Computern ausgeführt werden. In dieser Position sind die Synchronisationskosten noch teurer. Google hat einige Arbeiten durchgeführt und einige Forschungsarbeiten über funktionale Programmierung und Algorithmen veröffentlicht, die Sie einschreiben können. Dies ist für sie von entscheidender Bedeutung, da sie ein Problem mit der Skallierbarkeit haben.

Darüber hinaus können Sie mithilfe von verknüpften Listen problemlos einen Stapel im Haufen des Computers und sogar einen nicht kontinuierlichen Stapel erstellen. Dies wird bereits getan, um Stack-Trace in vielen Programmiersprachen zu generieren. Das ist also kein Problem.

OK, die funktionale Programmierung beinhaltet einige Einschränkungen. Es bringt aber auch eine natürliche Art und Weise, Probleme auszudrücken, die wir im modernen Computer haben und die in Paradigmen, an die wir gewöhnt sind, extrem schwer zu handhaben sind. Skalierbarkeit ist eine davon und wird zu einem echten Geschäft.

Jeder, der sich bereits mit einem komplexen Parallelsystem beschäftigt, weiß wovon ich spreche.

Also würde ich die Antwort nuancieren. Ja, funktionale Probleme gibt es mit moderner Hardware, aber auch mit einfacher alter Programmierung. Wie immer gibt es Vor- und Nachteile. Der Punkt ist, zu wissen, was sie sind, damit Sie die richtige Wahl treffen können, wenn Sie müssen.


0

Ich habe keine wirkliche Antwort, da ich den aktuellen Status nicht kenne oder auch nicht weiß, wie schwierig er sein würde, aber nur, weil der Compiler diese Dinge von der Eingabe sicherstellen würde, heißt das nicht unbedingt, dass die Ausgabe sie haben würde . Theoretisch könnte ein hinreichend intelligenter Compiler all diese Probleme umgehen, aber in der Praxis wird es sie wahrscheinlich immer geben.

Eine andere Sichtweise ist jedoch die Betrachtung der Geschichte der Lisp-Maschine. Wenn ich mich recht entsinne, waren sie ursprünglich dazu gedacht, die gleichen Probleme zu überwinden, die Lisp mit dem Unterschied zu den Maschinen zu der Zeit hatte. Die Entwicklung dieser Maschinen wurde schließlich gestoppt, da der Desktop schnell genug wurde, um die Ineffizienzen billiger zu machen, als eine andere Maschine zu unterstützen.

Mit Ausnahme der leistungskritischsten Anwendung sind FP-Sprachen im Allgemeinen immer noch schnell genug. Wenn Sie eine höhere Sprache wählen, sind Sie bereit, die Priorität für die Feinabstimmung der Steuerung und Leistung zu verringern, um eine sicherere, einfachere, wartbarere oder eine andere Priorität zu erreichen.

Letztendlich dreht sich bei der Programmierung alles um Kompromisse, daher muss man nur auswählen, was für das vorliegende Projekt wichtiger ist.


0

Das funktionale Paradigma impliziert zwar Unveränderlichkeit und Staatenlosigkeit, aber wir haben keine vollständig reinen Programmiersprachen. Selbst das reinste, Haskell, lässt Nebenwirkungen zu.

Zur Beantwortung Ihrer Frage zur Effizienz habe ich jedoch sowohl Haskell als auch Clojure verwendet und bei beiden keine Leistungsprobleme festgestellt.


1
Probleme beziehen sich auf Anforderungen ... Was ist mit leistungskritischen Bereichen? Hohe Parallelität ist dort wertvoll, aber wie hoch ist die Gesamtpunktzahl?
Reben

1
@vines: Ich habe keine der beiden Sprachen für eine leistungskritische Anwendung verwendet, daher kann ich nicht wirklich mit ihnen sprechen.
Larry Coleman

1
Kein großer Spaß ohne Nebenwirkungen, da Sie das Ergebnis nirgendwo speichern können.

@ Thorbjørn Ravn Andersen: ... auf eine andere Weise als dem Anrufer zurückzugeben, was erlaubt ist.
Reben
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.