it-swarm.com.de

Programmiersprache, in der jeder Funktionsaufruf / Block in einem separaten Thread ausgeführt wird?

Ich erstelle gerade eine Programmiersprache zum Spaß, bei der die Idee ist, dass jeder Funktionsaufruf/neuer Block (wenn Klauseln, Schleifen usw.) in einem separaten Thread funktioniert. Anstatt neue Threads zu erstellen, sollte der Standard sein, dass dies automatisch erfolgt. Wenn Sie möchten, dass es im Haupt-Thread ausgeführt wird, müssen Sie dies angeben.

Ich bin nicht so gut über Multithread-Parallelprogrammierung informiert, aber ich kenne die Grundlagen (Futures, Thread-sichere Objekte). Deshalb frage ich mich, wie eine solche Sprache syntaktisch aussehen könnte und ob es überhaupt möglich ist, damit zu beginnen? Das Ziel ist nicht, es "nützlich" zu machen, sondern eher zum Spaß und für eine Lernerfahrung.

(Es tut mir leid, wenn dies der falsche Ort zum Posten ist. Wenn ja, würde ich mich freuen, wenn Sie mich auf den richtigen Ort verweisen, an dem eine Frage wie meine erlaubt ist.)

26
Grimbox

jeder Funktionsaufruf/neuer Block (wenn Klauseln, Schleifen usw.) funktioniert in einem separaten Thread.

Lesen Sie viel mehr über Fortsetzungen und Continuation-Passing-Stil (und ihre Beziehung zu Threads oder Coroutinen) Ich schlage vor, SICP & LISP In Small Stücke . Außerdem bietet Programmiersprache Pragmatik einen nützlichen Überblick über mehrere Sprachen und hilft Ihnen beim Entwerfen Ihrer eigenen Sprachen.

Daher frage ich mich, wie eine solche Sprache syntaktisch aussehen könnte

Die Syntax spielt beim Erkunden von Ideen keine große Rolle. Semantik ist viel wichtiger. Ich schlage vor, zunächst eine S-expr -ähnliche Syntax zu verwenden (damit Sie einen Prototyp mit Scheme und dessen call/cc erstellen können).

Sobald Ihre Ideen klarer sind (nach einigen Experimenten), können Sie sie unter Lambda-the-Ultimate diskutieren. Sie können eine sexy Syntax definieren (was tatsächlich wichtig ist, wenn Sie möchten, dass die Leute Ihre Sprache übernehmen). und was auch zählt, ist die Qualität der Implementierung, eine kostenlose Software-Beispielimplementierung, die Dokumentation, die Standardbibliothek, die Fremdfunktionsschnittstelle usw.)

39

Vielleicht möchten Sie etwas über die Forschung zu Daten parallel Haskell lesen. Wenn Sie auf Youtube suchen, hat Simon Peyton Jones auch einige interessante Vorträge zu diesem Thema gehalten.

Wenn ich mich richtig an seine Vorträge erinnere, ist es in der reinen funktionalen Programmierung fast trivial, Möglichkeiten zu finden, um Threads zu erstellen. Sein Hauptproblem bei seiner Forschung ist, dass zu viele zu kurzlebig sind, so dass der Aufwand für das Erstellen von Threads und die Kommunikation ihrer Ergebnisse die Vorteile im Wesentlichen überwiegt der Parallelität. Zum Beispiel ist es einfach, einem Compiler beizubringen, 100 Threads zu drehen, um sum $ fmap (+1) <100 length vector> zu berechnen, aber lohnt sich der Overhead?

Der Trick besteht dann darin, Threads in vorteilhaften Größen zu konsolidieren, ohne den Programmierer zu belasten, dies manuell zu kennzeichnen. Es ist ein schwieriges Problem, das gelöst werden muss, um zukünftige PCs mit Tausenden von Kernen effektiv nutzen zu können.

37
Karl Bielefeldt

Genau das macht Erlang. Das Wiederverbinden der Threads erfolgt hauptsächlich mithilfe von Warteschlangen. Es ist ein brillantes Konzept, aber es ist anfangs etwas schwierig, den Kopf herumzureißen, wenn Ihr Hintergrund eher prozedurale Sprachen sind. Ich kann es nur empfehlen.

15
GenericJam

Zuerst würde ich empfehlen, dass Sie sich PROMELA ansehen, eine Sprache, die zur Beschreibung eines gleichzeitigen Algorithmus verwendet wird, damit ein Modellprüfer kann alle möglichen Ausführungen brutal erzwingen, um zu überprüfen, ob sie nicht in der Lage sind, sich falsch zu verhalten. (Gleichzeitige Programmierung ist notorisch schwer, um richtig zu machen, weshalb solche Überprüfungstechniken wichtig sind.) Es werden nicht alle Konstrukte in separaten Threads ausgeführt, aber es hat eine ziemlich seltsame Syntax und Semantik, weil es Der Fokus liegt auf dem Nichtdeterminismus gleichzeitiger Programme.

Der π-Kalkül ist ein schöner Ansatz zur Modellierung paralleler Berechnungen. Es ist schwer, sich zurechtzufinden, wenn Sie nicht das Buch Kommunizierende und mobile Systeme: Der Pi-Kalkül von Robin Milner erhalten. Es hat mir geholfen, über parallele Berechnungen im weiteren Sinne nachzudenken, dass "mehrere Threads auf einen gemeinsam genutzten Speicher zugreifen". Es ist ziemlich interessant, wie bedingte Aussagen, "gotos" usw. aus einfacheren, natürlich parallelen Grundelementen aufgebaut werden können.

In Bezug auf die Syntax ... ist der beste Weg, dies herauszufinden, einige Beispielprogramme zu schreiben. Schreiben Sie ein Programm, um ein Array zu sortieren, oder pingen Sie mehrere Server gleichzeitig an und melden Sie, welcher am schnellsten reagiert, oder versuchen Sie, ein Labyrinth parallel zu lösen, oder so weiter. Während Sie dies tun, werden die Dinge, die in Ihrer Syntax fehlen, offensichtlich und Sie können sie hinzufügen. Nachdem Sie mehrere Dinge hinzugefügt haben, fragen Sie sich, ob sie etwas gemeinsam haben. Wenn ja, finden Sie möglicherweise einen einfacheren Ansatz, der mehreren Zwecken dienen kann.

4
Artelius

Ähnliche Projekte wurden in der Vergangenheit versucht. Ich schlage vor, die Klassiker zu lesen, um Ideen zu plündern. (Alle Links gehen zu Wikipedia)

  • nity Diese Sprache wurde/wird verwendet, um parallele Programmierung zu unterrichten. Ich glaube nicht, dass es tatsächlich implementiert wurde. Die Syntax ist etwas kryptisch, aber im Grunde haben Sie eine Sammlung von Anweisungen, die in unbekannter Reihenfolge und wiederholt ausgeführt werden, bis nichts mehr zu tun ist. Dies kommt dem, was Sie verlangen, am nächsten.

  • Occam Diese Sprache wurde für die tatsächliche Verwendung entwickelt, hat sich aber nie wirklich durchgesetzt. Hier gibt es ein Schlüsselwort PAR, was bedeutet, dass eine Liste von Anweisungen parallel ausgeführt werden sollte.

  • Erlang Eine andere reale Sprache. Dieser wird von der Telekommunikationsfirma Ericsson verwendet und hat eine große Anhängerschaft. Sie haben viel Arbeit investiert, um die Parallelität praktisch und nutzbar zu machen.

  • Google GO Dies ist mein Favorit. Konzeptionell ähnlich wie Erlang, jedoch mit besserer Syntax und dem Gewicht von Google dahinter. Was könnte möglicherweise schief gehen?

Ich möchte mit einer Warnung schließen: Parallelität ist sehr schwer richtig zu machen. Die meisten Fehler in modernen Programmen sind das Ergebnis von Fehlern . Bist du sicher, dass du dorthin willst?

4
Stig Hemmer

Es ist möglich, aber für 99 +% aller denkbaren Anwendungen nicht sinnvoll. Logik ist typisch sequenzgebunden, es ist ein Fluss. Schritt für Schritt erreichen Sie eine Lösung für ein Problem, und die Reihenfolge der Schritte spielt eine Rolle, vor allem, weil die Ausgabe eines Schritts für den nächsten eingegeben wird.

In den wenigen Fällen, in denen viele Aufgaben unabhängig voneinander ausgeführt werden können, ist es in der Regel kostengünstig, sie nacheinander einzurichten, bevor sie parallel ausgeführt werden.

Ich denke, Sie sollten Ihre Zeit besser damit verbringen, zu lernen, wie Sie die Multithreading-Funktionen in Ihrer bevorzugten Programmiersprache verwenden.

3
Martin Maat

Obwohl dies keine Programmiersprache ist, sollten Sie sich VHDL ansehen. Es wird verwendet, um digitale Schaltkreise zu beschreiben, die natürlich alles parallel ausführen, es sei denn, Sie weisen sie ausdrücklich an, dies seriell zu tun. Es könnte Ihnen einige Ideen geben, wie Sie Ihre Sprache gestalten und für welche Art von Logik sie geeignet sein könnte.

2
OnePie

Clojure ist vielleicht einen Blick wert für einige Ideen.

http://clojure-doc.org/articles/language/concurrency_and_parallelism.html

Hier einige Gedanken: Wenn wir eine Recheneinheit, die unabhängig ausgeführt werden kann, als Aufgabe bezeichnen: 1. Aufgaben sind unabhängig und können gleichzeitig ausgeführt werden. 2. Unterschiedliche Aufgaben erfordern unterschiedliche Ressourcen und benötigen unterschiedliche Ausführungszeiten. 3. Daher sollten Aufgaben geplant werden für maximalen Durchsatz 4. Das einzige Programm, das als Scheduler fungieren kann, ist das Betriebssystem

Dinge wie Äpfel Grand Central Dispatch sind ein Versuch, einen solchen Planer bereitzustellen.

Das Obige bedeutet, dass die Verantwortung für die Ausführung von Aufgaben nicht unbedingt die der Programmiersprache ist.

Ein zweiter Gedanke ist, den Aufwand für die Programmierung paralleler Systeme so weit wie möglich zu verringern. Die einzige Möglichkeit, dies zu tun, besteht darin, alle Angaben darüber, wie etwas zu tun ist, aus dem Programm zu entfernen. Ein Programm sollte nur angeben, was zu tun ist, und der Rest sollte automatisch erfolgen.

Das Obige bedeutet wahrscheinlich, dass dynamische Sprachen und Just-in-Time-Kompilierung der richtige Weg sind.

2
foobar

Was Sie suchen, heißt impliziter Parallellismus, und es gibt Sprachen, die dieses Konzept untersucht haben, wie z. B. Sun/Oracle Fortress . Unter anderem werden (möglicherweise) Schleifen parallel ausgeführt.

Leider war es eingestellt und es gibt viele tote Links da draußen, aber Sie können immer noch ein paar PDFs finden, die dort herumschwirren, wenn Sie hart genug googeln:

https://www.eecis.udel.edu/~cavazos/cisc879-spring2008/papers/fortress.pdf (die Sprachspezifikation)

http://stephane.ducasse.free.fr/Teaching/CoursAnnecy/0506-Master/ForPresentations/Fortress-PLDITutorialSlides9Jun2006.pdf

http://www.Oracle.com/technetwork/systems/ts-5206-159453.pdf

http://dl.acm.org/citation.cfm?id=1122972 (paywalled)

Bemerkenswert ist, dass Sie normalerweise nicht für jede Anweisung/jeden Ausdruck einen tatsächlichen Thread starten möchten, da das Erstellen und Starten von Threads in der Regel teuer ist - stattdessen hätten Sie Pool von Threads, in denen Sie Teile veröffentlichen Arbeit, die erledigt werden muss . Aber das ist ein Implementierungsdetail.

2
gustafc

Dies kann in C++ recht einfach simuliert werden. Stellen Sie einfach sicher, dass "jeder" * Funktionsaufruf von einem std::future Implementiert wird. Die Behandlung des Rückgabewerts erfolgt einfach durch Aufrufen von .get() für die Zukunft.

Daher können Sie Ihre Sprache durch Kompilieren in C++ prototypisieren. Dies sagt uns auch, wie die Syntax aussehen würde: Der Hauptunterschied besteht darin, dass Sie den Aufrufpunkt (wo Eingabeargumente bereitgestellt werden) vom Rückgabepunkt (wo die Funktionsausgabe verwendet wird) trennen.

(*) Ich sage "jede Funktion", aber es liegt an Ihnen, was als Funktion zählt. Ist memset eine intrinsische oder eine Funktion? Ist die Zuweisung von Ganzzahlen oder die Zuweisung von benutzerdefinierten Typen ein Funktionsaufruf?

0
MSalters