Was ist Copy-on-Write?


133

Ich möchte wissen, was Copy-on-Write ist und wofür es verwendet wird. Der Begriff "Copy-on-Write-Array" wird in den Sun JDK-Tutorials mehrmals erwähnt, aber ich habe nicht verstanden, was er bedeutet.

Antworten:


155

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.


Alles, wofür ein reguläres Array verwendet wird ... In einigen Situationen führt diese Art von Strategie jedoch zu optimierten Ergebnissen.
Andrew Flanagan

3
@hhafez: Linux verwendet es bei clone()der Implementierung fork()- der Speicher des übergeordneten Prozesses ist für das untergeordnete Element COWed.
Kerrek SB

@hhafez Einige Dateisysteme verwenden CoW, z . B. BTRFS .
Geremia

Funktioniert SandboxIE so? Wenn ein Sandbox-Programm etwas überschreiben möchte, fängt sandboxie den Dateisystemvorgang ab, kopiert die Datei in den Sandbox-Ordner und lässt das Programm anstelle des Originals in die Sandbox-Datei schreiben. Heißt das Kopieren beim Schreiben?
Ronnie Matthews

Wie erfolgt die Zusammenführung schließlich? Wenn es N Kopien gibt, welche wird schließlich aufbewahrt, um sie beispielsweise auf der Festplatte zu speichern?
SimpleGuy

59

"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.


1
Wie wird der andere über Ihre neue Kopie informiert, wenn Sie eine Änderung vornehmen? Würden sie nicht die falschen Daten sehen?
Pulver366

12
@ Pulver366 - Nein, sie würden nicht die falschen Daten sehen, denn wenn Sie eine Änderung vornehmen, wird tatsächlich eine Kopie erstellt. Zum Beispiel haben Sie einen Datenblock namens A. Verfahren 1, 2, 3, 4jeder 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 3möchte der Prozess eine Änderung an seiner Kopie vornehmen. Der AProzess erstellt 3nun tatsächlich eine Kopie Aund erstellt einen neuen Datenblock mit dem Namen B. Prozess 1, 2, 4sind Block noch ALesevorgang 3ist jetzt liest B.
Puddler

1
@Puddler was passiert, wenn Änderungen in 'A' vorgenommen werden. Alle Prozesse werden die aktualisierten Informationen lesen oder alt?
Entwickler

3
@Developer: Nun, welcher Prozess auch immer eine Änderung vornimmt, Asollte eine neue Kopie erstellen. Wenn Sie sich fragen, was passiert, wenn ein völlig neuer Prozess eintritt und sich ändert, geht Ameine 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.
Puddler

10

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.


3
"vfork folgt dem Konzept des Copy-on-Write". Bitte erwägen Sie, diese Zeile zu ändern. vforkverwendet 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 vforketwas im gemeinsamen Raum verändert wird!
Pavan Manjunath

Stimme Pavan voll und ganz zu. Entfernen Sie die Zeilen "vfork folgt dem Konzept des Copy-on-Write". Heute wird COW in Fork als Optimierung verwendet, sodass es sich wie eine Vfork verhält und keine Kopie der Daten der Eltern für den untergeordneten Prozess erstellt (wenn wir nur exec * in child aufrufen)
Shekhar Kumar

7

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.


2

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.


0

Es wird auch in Ruby 'Enterprise Edition' verwendet, um Speicherplatz zu sparen.


2
Ich glaube nicht, dass er in diesem Sinne "gebraucht" meinte.
Spydon

0

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.


0

Es ist ein Speicherschutzkonzept. In diesem Compiler wird eine zusätzliche Kopie erstellt, um Daten im untergeordneten Element zu ändern. Diese aktualisierten Daten spiegeln sich nicht in den übergeordneten Daten wider.


0

Hier folgt eine COW-Python-Implementierung (Copy-on-Write) unter Verwendung des Decorator-Entwurfsmusters . Ein Verweis auf ein unveränderliches ValueObjekt wird von einem veränderlichen CowValueObjekt (dem Dekorateur) gehalten. Das CowValueObjekt leitet alle Leseanforderungen an das unveränderliche ValueObjekt weiter und fängt alle Schreibanforderungen ab, indem es ein neues unveränderliches ValueObjekt mit dem richtigen Status erstellt. Das CowValueObjekt muss flach zwischen Variablen kopiert werden, damit das ValueObjekt 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)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.