C++ und moderne Parallelisierung unvereinbar?
-
Was du uns also eigentlich sagen willst ist nicht, dass C++ irgendein besonderes fundamentales Problem mit Threading hätte, sondern dass du lieber in einer Sprache arbeiten würdest in der deine "Regeln" schon integriert sind?
-
cooky451 schrieb:
Was du uns also eigentlich sagen willst ist nicht, dass C++ irgendein besonderes fundamentales Problem mit Threading hätte, sondern dass du lieber in einer Sprache arbeiten würdest in der deine "Regeln" schon integriert sind?
Es ist wie mit C und OOP/Templates: Prinzipiell machbar, aber ohne Sprachunterstützung einfach unpraktikabel.
-
shreadder schrieb:
cooky451 schrieb:
Was du uns also eigentlich sagen willst ist nicht, dass C++ irgendein besonderes fundamentales Problem mit Threading hätte, sondern dass du lieber in einer Sprache arbeiten würdest in der deine "Regeln" schon integriert sind?
Es ist wie mit C und OOP/Templates: Prinzipiell machbar, aber ohne Sprachunterstützung einfach unpraktikabel.
Ich mach's mal wie im Projekte-Forum.
Um als Anti-C++-Troll qualifizierte Antwort im C++-Forum zu bekommen, musst Du einen angemessenen Stundenlohn anbieten. Wir lösen Dein Problem, wenn Du bereit bist, zu zahlen.
-
Ich wiederhole meine Frage von vorhin: Wie würde STM in C++ aussehen?
-
shreadder schrieb:
Ich wiederhole meine Frage von vorhin: Wie würde STM in C++ aussehen?
Wieviel? Für 100€ sage ich Dir, daß Tasks gar nicht Threads sind.
-
shreadder schrieb:
Man sieht ja wohin das führt:
Das ist Bullshit. Es bedeutet nur: benutze keine Threadingbibliotek wenn du Tasking brauchst. Du benutzt auch nicht asio wenn dein Programm nur serielle i/o braucht(wobei du dir das ja alles mit strand zurechthacken könntest und dich dann darüber beschweren kannst dass io_service::post nicht synchron ist.).
Regel 3: Verwende kein async/future, weil broken
Aus dem Artikel sowie den beiden verlinkten geht nicht hervor, dass sie broken sind.
Zitat : "If you expected std::async to be just syntactic sugar over thread creation, you can stop reading right now, because that’s what it is. If you expected more, read on.
Don’t get me wrong, std::async combines several useful concurrency concepts into a nice package: It provides a std::future for the return value, and hides the std::promise side of the future. It also provides options to run a task synchronously. (See the Appendix for a short refresher.)".
Der Artikel über futures sagte auch nicht, dass futures broken sind, sondern dass ein (wichtiges) Feature fehlt.
Regel 4: Schreibe nicht in nicht-task-lokale Variablen
Regel 5: Rufe keine Funktion auf, die in nicht-lokale-Variablen schreibt (da fängts schon an)Äquivalent zu: "hab keine Seiteneffekte". Sehe ich als nicht problematisch an.
Regel 6: vermeide const in Tasks, mach Objekte entweder const-only (immutable) oder mutable-only (d.h. ohne const Zugriff), da sonst const != konstant
[volkard]Quatsch[/volkard]
So wird ein Schuh draus: Funktionsargumente dürfen nicht aliasen.Parallelisierung war noch nie einfach, aber C++ kommt da an eine Grenze, wo selbst einfache Task-Modelle nicht vernünftig (ohne Garantien und nur mit Verboten) umsetzbar sind.
Man muss da aber den Startpunkt betrachten: Selbst mit allen von dir angebrachten Verboten ist C++ noch immer weniger bschränkt als Haskell. Sieht man bereits bei Regel 6, da würde bei Haskell stehen: Funktionsargumente sind immutable.
-
otze schrieb:
... aber imho ist das nicht viel anders als in einer C++ Threading bibliothek zu sagen: "Funktionen dürfen keine Seiteneffekte haben.". Der einzige Unterschied ist, dass Haskell dieses garantiert. Das ist ein wichtiger Unterschied aber nicht game-changing, weil man dies auch durch einen Contract lösen kann.
Kann man nicht. Ich beschäftige mich auch gerade mit dem Thema und das hier passt ziemlich gut: Threads Cannot Be Implemented As a Library
So richtig blicke ich aber noch nicht durch.
Ich meine man müsste Anweisungen anbieten, die das Memory Model festlegen. Der Compiler kann es nämlich nicht können. Der Grund ist, dass man erst richtig Performance gewinnt wenn man Data races zulässt und trotzdem das Richtige raus kommt. Sequential consistency löst zwar die Data races, entfernt aber auch den Performance-Gewinn und ist daher inakzeptabel.
-
Wäre mir neu, dass man map-reduce nicht gut implementieren könnte :).
-
Haskell ist im Bereich von paralleler Programmierung sehr weit. Zum einen, weil sie aus den Erfahrungen anderer Programmiersprachen wie Erlang gelernt haben, zum anderen weil sich Mathematiker mit dem Problem befassen. Weiterhin hat sie nicht den Anspruch low-level zu sein.
C++ noch immer weniger bschränkt als Haskell. Sieht man bereits bei Regel 6, da würde bei Haskell stehen: Funktionsargumente sind immutable.
Nun, Haskell loest die Probleme auf andere Art und Weise, C++ ist deswegen nicht weniger eingeschraenkt.
-
shreadder schrieb:
Aufbauend auf diesem Blogpost von einem bekannten C++-Guru: http://bartoszmilewski.com/2013/09/19/edward-chands/
Den einen oder anderen seiner Blogartikel habe ich wohl gelesen, auch die zwei, die er hier im Abschnitt zur Nebenläufigkeit referenzierte ("broken promises", "task based parallelism"). Aber irgendwie finde ich davon kaum etwas überzeugend. Seine Seite flog dann irgendwann aus meinem Feed-Reader raus.
Bei diesem neuen Artikel werde ich das Gefühl nicht los, als würde er übertreiben, als würde er hier und da Äpfel mit Birnen vergleichen. Z.B. hier:
D at least has the notion of deep constness [...] But C++ doesn’t support any of this [...]
Was habe ich daran auszusetzen? Er erwähnt "deep constness" als sei das ein Feature, welches in C++ fehle. Dabei ist "deep constness" in D der Versuch, Komposition trotz aufgezwungene Indirektion zu emulieren. Komposition wird in C++ aber direkt unterstützt. In C++ haben wir diese drei Objekt<->Objekt beziehungen:
- Objekt A betitzt Objekt B. Objekt B ist Subobjekt von A (ein Teil davon). Hier verhält sich const genauso, wie man es will.
- Objekt A kennt Objekt B über einen Zeiger. B ist nicht Teil von A. Warum sollte sich die constness von A an B übertragen? Denken wir zB. an Iteratoren.
- Objekt A besitzt Objekt B, aber nur die Adresse von B ist Teil von A. Das kann nützlich sein (B könnte optional oder polymorph sein) Hier muss man eh Hand anlegen: Kopierkonstruktor/Zuweisungsoperator deaktivieren oder selbst implementieren, Destruktor schreiben. Da tut es zwecks Kapselung auch nicht weh, wenn man einen Accessor anbietet, der sich um Constness kümmern (wie z.b. operator[] bei std::vector).
"deep constness" bei Zeigern ist eher unnütz, wenn man sie einfach Kopieren kann:
struct foo { deep_const_ptr<int> ptr; }; void foo(const foo& f) { // *(f.ptr) ist ein const int Lvalue foo g = f; *(g.ptr) = 42; // oops! das geht ja sogar! }Sorry, ich werde das Gefühl nicht los, dass die, die sich über das Fehlen von "deep constness" bei C++ beklagen, nicht klar im Kopf sind. Alexandrescu hat da auch schon komische Kommentare in comp.lang.c++ gelassen, wo ich mich fragen muss, ob er "const" eigentlich verstanden hat. (Er wollte mal const-Überladungen für Konsruktoren haben).
shreadder schrieb:
std::async und std::future völlig broken,
Kannst du bitte zusammenfassen, was daran "völlig broken" ist?
shreadder schrieb:
std::mutex/std::thread/std::condition_variable sind viel zu lowlevel um sie sinnvoll einsetzen zu können
Wo ist das jetzt ein Argument für die "Unvereinbarkeit" von C++ mit "moderner Parallelisierung"? Willst Du behaupten, dass man da nicht drauf aufbauen kann?
shreadder schrieb:
Keinerlei Schutzmechanismen in der Sprache gegen Data Races u.Ä. (pure, immutable)
Das ist mir persönlich ein bisschen zu abstrakt. Am besten erklärst du mir das mal mit schönen Beispielen.
shreadder schrieb:
Daher sind STM, Tasks, etc. praktisch unmöglich sinnvoll umzusetzen un
d C++ ist ungeeignet für modernes ThreadingMit STM kenne ich mich zu wenig aus, als dass ich dazu was sagen kann. Das mit den Tasks lasse ich mir ja von dir nochmal erklären.