Ich höre viel über funktionale Sprachen und wie sie gut skalieren, weil es keinen Zustand um eine Funktion gibt; und deshalb kann diese Funktion massiv parallelisiert werden.
Das macht mir aber wenig Sinn, weil fast alle praxisnahen Programme der realen Welt brauchen. Ich finde es auch interessant, dass die meisten Hauptskalierungsbibliotheken, d.h. MapReduce, typischerweise in imperativen Sprachen wie C oder C ++ geschrieben sind.
Ich würde gerne von dem funktionellen Camp hören, wo dieser Hype, von dem ich höre, kommt ...
Es ist wichtig, ein Wort hinzuzufügen: "Es gibt keinen freigegebenen Status".
Jedes sinnvolle Programm (in jeder Sprache) verändert den Zustand der Welt. Aber (einige) funktionale Sprachen machen es unmöglich, von mehreren Threads gleichzeitig auf dieselbe Ressource zuzugreifen. Das Fehlen des freigegebenen -Zustands macht Multithreading sicher.
Funktionale Sprachen wie Haskell, Scheme und andere haben sogenannte "pure functions". Eine reine Funktion ist eine Funktion ohne Nebenwirkungen. Es ändert keinen anderen Zustand im Programm. Dies ist per Definition threadsafe.
Natürlich können Sie reine Funktionen in Imperativsprachen schreiben. Sie finden auch Multiparadigmensprachen wie Python, Ruby und sogar C #, wo Sie imperative Programmierung, funktionale Programmierung oder beides machen können.
Aber der Punkt von Haskell (usw.) ist, dass Sie nicht eine nicht-reine Funktion schreiben können. Nun, das ist nicht streng richtig, aber es ist meistens wahr.
Ähnlich haben viele imperative Sprachen unveränderliche Objekte aus dem gleichen Grund. Ein unveränderliches Objekt ist ein Objekt, dessen Zustand sich nach der Erzeugung nicht ändert. Wiederum per definitionem ist ein unveränderliches Objekt threadsafe.
Sie sprechen über zwei verschiedene Dinge und merken es nicht.
Ja, die meisten echten Programme haben irgendwo , aber wenn Sie Multithreading durchführen wollen, sollte dieser Zustand nicht überall sein, und tatsächlich, je weniger Orte es ist in, desto besser. In funktionalen Programmen ist der Standard kein Zustand, und Sie können den Status genau dort eingeben, wo Sie ihn brauchen und nirgendwo sonst. Die Teile, die sich mit dem Zustand befassen, werden nicht so einfach multithread sein, aber da der Rest Ihres Programms frei von Nebeneffekten ist und es somit egal ist, in welcher Reihenfolge diese Teile ausgeführt werden, beseitigt es eine große Parallelisierungsbarriere .
Das macht mir aber wenig Sinn, weil fast alles real ist Praktische Programme brauchen / haben einen Staat, um den sie sich kümmern müssen.
Du wärst überrascht! Ja, alle Programme benötigen einen bestimmten Zustand (insbesondere E / A), aber oft brauchen Sie nicht viel mehr. Nur weil die meisten Programme viel Staat haben, bedeutet das nicht, dass sie es brauchen.
Das Programmieren in einer funktionalen Sprache ermutigt Sie, weniger Status zu verwenden, und somit werden Ihre Programme leichter parallelisierbar.
Viele funktionale Sprachen sind "unrein", was bedeutet, dass sie einige Zustände erlauben. Haskell hat das nicht, aber Haskell hat Monaden, die im Grunde genommen etwas aus dem Nichts herausholen lassen: Man bekommt den Zustand mit staatenlosen Konstrukten. Monaden sind ein wenig fummelig, weshalb Haskell Ihnen einen starken Anreiz gibt, den Staat auf einen so kleinen Teil Ihres Programms wie möglich einzuschränken.
Ich finde es auch interessant, dass die meisten großen Skalierungsbibliotheken, d. h. MapReduce, werden normalerweise in imperativen Sprachen wie C oder C ++ geschrieben.
Das Programmieren paralleler Anwendungen ist in C / C ++ "hart". Deshalb ist es am besten, all die gefährlichen Dinge in einer Bibliothek zu tun, die stark getestet und inspiziert wird. Aber Sie erhalten immer noch die Flexibilität und Leistung von C / C ++.
Funktionen höherer Ordnung. Betrachten Sie eine einfache Reduktionsoperation, die die Elemente eines Arrays summiert. In einer imperativen Sprache schreiben Programmierer normalerweise selbst eine Schleife und führen Reduktionen Element für Element durch.
Aber dieser Code ist nicht einfach zu multi-threaded. Wenn Sie eine Schleife schreiben, gehen Sie von einer Reihenfolge der Operationen aus und Sie müssen angeben, wie Sie von einem Element zum nächsten gelangen. Sie möchten wirklich nur "sum the array" sagen und den Compiler oder die Runtime oder was auch immer entscheiden lassen, wie Sie das Array durcharbeiten, die Aufgabe nach Bedarf zwischen mehreren Kernen aufteilen und diese Ergebnisse kombinieren . Anstatt also eine Schleife zu schreiben, in die ein zusätzlicher Code eingebettet ist, besteht die Alternative darin, etwas zu übergeben, das "Addition" darstellt, und zwar in eine Funktion, die das Divivieren ermöglicht. Sobald Sie das tun, schreiben Sie funktional. Sie übergeben eine Funktion (Addition) in eine andere Funktion (den Reduzierer). Wenn Sie auf diese Weise schreiben, macht es nicht nur lesbareren Code, sondern wenn Sie die Architektur ändern oder für heterogene Architekturen schreiben möchten, müssen Sie nicht den Sommer, sondern nur den Reducer ändern. In der Praxis könnten Sie viele verschiedene Algorithmen haben, die alle einen Reduzierer teilen, also ist das ein großer Gewinn.
Dies ist nur ein einfaches Beispiel. Vielleicht möchten Sie darauf aufbauen. Funktionen zum Anwenden anderer Funktionen auf 2D-Arrays, Funktionen zum Anwenden von Funktionen auf Baumstrukturen, Funktionen zum Kombinieren von Funktionen zum Anwenden von Funktionen (z. B. wenn Sie eine hierarchische Struktur mit Bäumen oben und Arrays unten haben) usw.
Tags und Links multithreading functional-programming