Antworten:
Ich wollte meine eigene Erklärung schreiben, aber dieser Wikipedia-Artikel fasst es ziemlich gut zusammen.
Hier ist das Grundkonzept:
Copy-on-Write (manchmal auch als "COW" bezeichnet) ist eine Optimierungsstrategie, die bei der Computerprogrammierung verwendet wird. Die Grundidee ist, dass wenn mehrere Anrufer nach Ressourcen fragen, die anfangs nicht unterscheidbar sind, Sie ihnen Zeiger auf dieselbe Ressource geben können. Diese Funktion kann beibehalten werden, bis ein Aufrufer versucht, seine "Kopie" der Ressource zu ändern. Zu diesem Zeitpunkt wird eine echte private Kopie erstellt, um zu verhindern, dass die Änderungen für alle anderen sichtbar werden. All dies geschieht transparent für die Anrufer. Der Hauptvorteil besteht darin, dass keine private Kopie erstellt werden muss, wenn ein Anrufer niemals Änderungen vornimmt.
Auch hier ist eine Anwendung einer allgemeinen Verwendung von COW:
Das COW-Konzept wird auch bei der Wartung von Sofort-Snapshots auf Datenbankservern wie Microsoft SQL Server 2005 verwendet. Instant-Snapshots behalten eine statische Ansicht einer Datenbank bei, indem eine Kopie der Daten vor der Änderung gespeichert wird, wenn die zugrunde liegenden Daten aktualisiert werden. Sofortige Snapshots werden zum Testen von Anwendungen oder momentabhängigen Berichten verwendet und sollten nicht zum Ersetzen von Sicherungen verwendet werden.
clone()
der Implementierung fork()
- der Speicher des übergeordneten Prozesses ist für das untergeordnete Element COWed.
"Beim Schreiben kopieren" bedeutet mehr oder weniger, wie es sich anhört: Jeder hat eine einzige gemeinsam genutzte Kopie derselben Daten, bis sie geschrieben werden , und dann wird eine Kopie erstellt. Normalerweise wird Copy-on-Write verwendet, um Probleme mit Parallelität zu lösen. In ZFS werden beispielsweise Datenblöcken auf der Festplatte Copy-on-Write zugewiesen. Solange keine Änderungen vorgenommen wurden, behalten Sie die ursprünglichen Blöcke bei. Eine Änderung hat nur die betroffenen Blöcke geändert. Dies bedeutet, dass die Mindestanzahl neuer Blöcke zugewiesen wird.
Diese Änderungen werden normalerweise auch transaktional implementiert , dh sie haben die ACID- Eigenschaften. Dadurch werden einige Parallelitätsprobleme beseitigt, da dann garantiert wird, dass alle Updates atomar sind.
A
. Verfahren 1
, 2
, 3
, 4
jeder möchte eine Kopie davon machen und beginnen , es zu lesen, in einem „Copy - on - Write“ System nichts kopiert noch alles noch zu lesen A
. Jetzt 3
möchte der Prozess eine Änderung an seiner Kopie vornehmen. Der A
Prozess erstellt 3
nun tatsächlich eine Kopie A
und erstellt einen neuen Datenblock mit dem Namen B
. Prozess 1
, 2
, 4
sind Block noch A
Lesevorgang 3
ist jetzt liest B
.
A
sollte eine neue Kopie erstellen. Wenn Sie sich fragen, was passiert, wenn ein völlig neuer Prozess eintritt und sich ändert, geht A
meine Erklärung dafür nicht wirklich ins Detail. Das wäre implementierungsspezifisch und erfordert Kenntnisse darüber, wie der Rest der Implementierung funktionieren soll, wie z. B. Sperren von Dateien \ Daten usw.
Ich werde nicht die gleiche Antwort auf Copy-on-Write wiederholen. Ich denke, Andrews Antwort und Charlies Antwort haben es bereits sehr deutlich gemacht. Ich werde Ihnen ein Beispiel aus der OS-Welt geben, um nur zu erwähnen, wie weit verbreitet dieses Konzept ist.
Wir können einen neuen Prozess verwenden fork()
oder vfork()
erstellen. vfork folgt dem Konzept des Copy-on-Write. Beispielsweise teilt der von vfork erstellte untergeordnete Prozess das Daten- und Codesegment mit dem übergeordneten Prozess. Dies beschleunigt die Gabelzeit. Es wird erwartet, dass vfork verwendet wird, wenn Sie exec gefolgt von vfork ausführen. Daher erstellt vfork den untergeordneten Prozess, der Daten und Codesegmente mit seinem übergeordneten Prozess teilt. Wenn wir jedoch exec aufrufen, wird das Image einer neuen ausführbaren Datei in den Adressraum des untergeordneten Prozesses geladen.
vfork
verwendet KEINE KUH. In der Tat, wenn das Kind etwas schreibt, kann es zu undefiniertem Verhalten und nicht zum Kopieren von Seiten führen !! In der Tat kann man sagen, dass der umgekehrte Weg etwas wahr ist. COW verhält sich so, als ob vfork
etwas im gemeinsamen Raum verändert wird!
Um nur ein weiteres Beispiel zu nennen: Mercurial verwendet Copy-on-Write , um das Klonen lokaler Repositorys zu einem wirklich "billigen" Vorgang zu machen.
Das Prinzip ist das gleiche wie in den anderen Beispielen, außer dass Sie von physischen Dateien anstelle von Objekten im Speicher sprechen. Ein Klon ist zunächst kein Duplikat, sondern eine feste Verbindung zum Original. Wenn Sie Dateien im Klon ändern, werden Kopien geschrieben, um die neue Version darzustellen.
Ich habe diesen guten Artikel über zval in PHP gefunden, in dem auch COW erwähnt wurde:
Copy On Write (abgekürzt als 'COW') ist ein Trick zum Speichern von Speicher. Es wird allgemeiner in der Softwareentwicklung verwendet. Dies bedeutet, dass PHP den Speicher kopiert (oder einen neuen Speicherbereich zuweist), wenn Sie in ein Symbol schreiben, wenn dieses bereits auf ein zval zeigte.
Ein gutes Beispiel ist Git, das eine Strategie zum Speichern von Blobs verwendet. Warum werden Hashes verwendet? Zum Teil, weil diese einfacher durchzuführen sind, aber auch, weil es einfacher ist, eine COW-Strategie zu optimieren. Wenn Sie mit wenigen Dateiänderungen ein neues Commit durchführen, ändert sich die überwiegende Mehrheit der Objekte und Bäume nicht. Daher verweist das Commit durch verschiedene Zeiger aus Hashes auf eine Reihe bereits vorhandener Objekte, wodurch der zum Speichern des gesamten Verlaufs erforderliche Speicherplatz viel kleiner wird.
Hier folgt eine COW-Python-Implementierung (Copy-on-Write) unter Verwendung des Decorator-Entwurfsmusters . Ein Verweis auf ein unveränderliches Value
Objekt wird von einem veränderlichen CowValue
Objekt (dem Dekorateur) gehalten. Das CowValue
Objekt leitet alle Leseanforderungen an das unveränderliche Value
Objekt weiter und fängt alle Schreibanforderungen ab, indem es ein neues unveränderliches Value
Objekt mit dem richtigen Status erstellt. Das CowValue
Objekt muss flach zwischen Variablen kopiert werden, damit das Value
Objekt gemeinsam genutzt werden kann.
import abc
import copy
class BaseValue(abc.ABC):
@abc.abstractmethod
def read(self):
raise NotImplementedError
@abc.abstractmethod
def write(self, data):
raise NotImplementedError
class Value(BaseValue):
def __init__(self, data):
self.data = data
def read(self):
return self.data
def write(self, data):
pass
class CowValue(BaseValue):
def __init__(self, data):
self.value = Value(data)
def read(self):
return self.value.read()
def write(self, data):
self.value = Value(data)
v = CowValue(1)
w = copy.copy(v) # shares the immutable Value object
assert v.read() == w.read()
assert id(v.value) == id(w.value)
w.write(2) # creates a new immutable Value object with the correct state
assert v.read() != w.read()
assert id(v.value) != id(w.value)