Race Conditions können sicherlich auch bei ungeteilten Datenstrukturen noch bestehen. Beachten Sie Folgendes:
B asks A for the currentCount
C asks A for the currentCount
B sends A (newDataB, currentCount + 1)
A stores newDataB at location currentCount+1
C sends A (newDataC, currentCount + 1)
A stores newDataC at currentCount + 1 (overwriting newDataB; race condition)
Diese Race-Bedingung in einem privaten wandelbaren Zustand erfordert, aber keine änderbaren Datenstrukturen geteilt und nicht einmal wandelbaren Zustand in B oder C erfordert Es gibt nichts, B oder C ist tun können, um zu verhindern diese Wettlaufbedingung, ohne den Vertrag zu verstehen, den A anbietet.
Sogar Haskell kann diese Art von Race Conditions erleiden, sobald der Zustand in die Gleichung eintritt, und der Zustand ist sehr schwer vollständig aus einem realen System zu eliminieren. Schließlich möchten Sie, dass Ihr Programm mit der Realität interagiert und dass die Realität zustandsbehaftet ist.Wikipedia gibt a helpful race condition example in Haskell mit STM.
Ich stimme zu, dass gute unveränderliche Datenstrukturen die Dinge erleichtern könnten (Go hat sie nicht wirklich). Veränderliche Kopien tauschen ein Problem gegen ein anderes. Sie können die Daten eines anderen nicht versehentlich ändern. Auf der anderen Seite, können Sie denken, dass Sie die echte ändern, wenn Sie eigentlich nur eine Kopie ändern, was zu einer anderen Art von Fehler führt. Sie müssen den Vertrag auf jeden Fall verstehen.
Aber letztlich neigt Go die Geschichte von C auf Parallelität folgen: Sie einige Besitzregeln für Ihren Code bilden (wie @ tux21b Angebote) und stellen Sie sicher, dass Sie sie immer folgen, und wenn Sie es perfekt machen werde es alle arbeiten großartig, und wenn du jemals einen Fehler machst, dann ist es offensichtlich deine Schuld, nicht die Sprache.
(Versteh mich nicht falsch, Ich mag Go, eine ganze Menge wirklich Und es bietet einige nette Tools in die Parallelität leicht machen es einfach nicht viele Sprach-Tools nicht bieten korrekte zu helfen, machen Gleichzeitigkeit Das ist... Das heißt, die Antwort von tux21b bietet viele gute Ratschläge, und der Race Detector ist definitiv ein mächtiges Werkzeug, um die Rennbedingungen zu reduzieren.Es ist einfach kein Teil der Sprache, und es geht um Testen, nicht um Korrektheit, sie sind nicht die Die gleiche Sache.)
EDIT: Auf die Frage, warum unveränderliche Datenstrukturen die Dinge einfacher machen, ist dies die Erweiterung Ihres Ausgangspunkts: Erstellen eines Vertrags, wo mehrere Parteien nicht die gleichen Daten ändern eine Struktur. Wenn die Datenstruktur unveränderlich ist, dann kommt das kostenlos ...
Viele Sprachen verfügen über eine umfangreiche Sammlung unveränderlicher Sammlungen und Klassen. C++ ermöglicht Ihnen const
einfach alles. Objective-C verfügt über unveränderbare Auflistungen mit änderbaren Unterklassen (wodurch eine andere Gruppe von Mustern erstellt wird als const
). Scala hat verschiedene veränderbare und unveränderbare Versionen vieler Sammlungsarten, und es ist allgemein üblich, ausschließlich die unveränderlichen Versionen zu verwenden. Die Angabe der Unveränderlichkeit in einer Methodensignatur ist ein wichtiger Hinweis auf den Vertrag.
Wenn Sie eine []byte
an eine Goroutine übergeben, gibt es keine Möglichkeit, aus dem Code zu erfahren, ob die Goroutine beabsichtigt, die Schicht zu ändern, noch wann Sie die Schicht selbst modifizieren können. Dort tauchen Muster auf, aber sie sind wie C++ - Objektbesitz vor der Umzugs-Semantik; viele gute Ansätze, aber keine Möglichkeit zu wissen, welcher verwendet wird. Es ist eine kritische Sache, die jedes Programm richtig machen muss, aber die Sprache gibt Ihnen keine guten Werkzeuge, und es gibt kein universelles Muster, das von Entwicklern benutzt wird.
Race-Bedingungen sind schwer zu debuggen, es ist auch schwierig zu meistern, sie zu vermeiden. Ich würde vorschlagen, über die hier beschriebenen Muster von Rob Pike http://vimeo.com/49718712 nachzudenken, während er bestimmte Konstrukte durchläuft, wie Kanäle und CSP-Semantiken eine Anwendung durch Design sicher machen, anstatt sich um alle Probleme zu kümmern, die mit Mutexen verbunden sind. Es tut mir leid, wenn dies Ihre Frage nicht beantwortet, aber ich hoffe, es öffnet mehr Türen zu neuen Ideen. – ymg
Danke für den Link. Ja, Rennbedingungen sind schwer zu verhindern, aber noch schwieriger zu debuggen! Ich denke, eine unveränderliche Version der Sammlungen würde das Problem in gewissem Maße lindern, aber dann sind wir wieder im Hinterkopf der funktionalen Programmierung. – tldr
Dort sind _andere unveränderlich-basierte/funktionale Sprachen (wie F #), aber es geht wirklich um Stil. Sie haben recht, wenn Sie mehr Speicher benötigen, aber richtiges Design kann einen Teil des Overheads eliminieren. Zum Beispiel können Write-On-Modifikationsarrays im 'n log n'-Raum (oder weniger für einige potentielle Fälle) im Durchschnitt anstatt in einem naiven' 2n' gemacht werden. Obwohl Sprach/Optimizer-Unterstützung einige verrückte Dinge für die speziell entwickelten Sprachen tun kann ... –