Réponses:
J'allais rédiger ma propre explication, mais cet article de Wikipedia résume assez bien la situation.
Voici le concept de base:
La copie sur écriture (parfois appelée «COW») est une stratégie d'optimisation utilisée dans la programmation informatique. L'idée fondamentale est que si plusieurs appelants demandent des ressources qui sont initialement impossibles à distinguer, vous pouvez leur donner des pointeurs vers la même ressource. Cette fonction peut être maintenue jusqu'à ce qu'un appelant essaie de modifier sa "copie" de la ressource, à quel point une véritable copie privée est créée pour éviter que les modifications ne deviennent visibles par tout le monde. Tout cela se passe de manière transparente pour les appelants. Le principal avantage est que si un appelant n'effectue aucune modification, aucune copie privée n'a jamais besoin d'être créée.
Voici également une application d'une utilisation courante de COW:
Le concept COW est également utilisé dans la maintenance des instantanés instantanés sur des serveurs de base de données comme Microsoft SQL Server 2005. Les instantanés instantanés préservent une vue statique d'une base de données en stockant une copie de pré-modification des données lorsque les données sous-jacentes sont mises à jour. Les instantanés instantanés sont utilisés pour tester des utilisations ou des rapports dépendant du moment et ne doivent pas être utilisés pour remplacer les sauvegardes.
clone()
pour implémenter fork()
- la mémoire du processus parent est COWed pour l'enfant.
«Copier à l'écriture» signifie plus ou moins ce que cela ressemble: tout le monde a une seule copie partagée des mêmes données jusqu'à ce qu'elles soient écrites , puis une copie est faite. Habituellement, la copie sur écriture est utilisée pour résoudre les types de problèmes de concurrence. Dans ZFS , par exemple, les blocs de données sur le disque sont alloués en copie sur écriture; tant qu'il n'y a pas de changements, vous conservez les blocs d'origine; un changement n'a changé que les blocs affectés. Cela signifie que le nombre minimum de nouveaux blocs est alloué.
Ces modifications sont également généralement implémentées pour être transactionnelles , c'est-à-dire qu'elles ont les propriétés ACID . Cela élimine certains problèmes de concurrence, car vous êtes alors assuré que toutes les mises à jour sont atomiques.
A
. Processus 1
, 2
, 3
, 4
chacun veulent faire une copie et commencer à le lire, dans une « copie à l' écriture » rien du système est copié et pourtant tout est en train de lire encore A
. Désormais, le processus 3
souhaite modifier sa copie de A
, le processus 3
va maintenant en faire une copie A
et créer un nouveau bloc de données appelé B
. Processus 1
, 2
, 4
sont encore la lecture bloc A
processus 3
est en train de lire B
.
A
devrait créer une nouvelle copie. Si vous vous demandez ce qui se passe si un processus entièrement nouveau arrive et change, A
mon explication n'est pas vraiment assez détaillée pour cela. Ce serait spécifique à l'implémentation et nécessiterait des connaissances sur la façon dont vous voulez que le reste de l'implémentation fonctionne, comme le verrouillage de fichier \ données, etc.
Je ne répéterai pas la même réponse sur la copie sur écriture. Je pense que la réponse d'Andrew et la réponse de Charlie ont déjà été très clair. Je vais vous donner un exemple du monde OS, juste pour mentionner à quel point ce concept est largement utilisé.
Nous pouvons utiliser fork()
ou vfork()
créer un nouveau processus. vfork suit le concept de copie sur écriture. Par exemple, le processus enfant créé par vfork partagera les données et le segment de code avec le processus parent. Cela accélère le temps de fourche. Il est prévu d'utiliser vfork si vous exécutez exec suivi de vfork. Ainsi, vfork créera le processus enfant qui partagera les données et le segment de code avec son parent, mais lorsque nous appelons exec, il chargera l'image d'un nouvel exécutable dans l'espace d'adressage du processus enfant.
vfork
n'utilise PAS COW. En fait, si l'enfant écrit quelque chose, cela peut entraîner un comportement indéfini et ne pas copier de pages !! En fait, vous pouvez dire que l'inverse est un peu vrai. COW agit comme vfork
jusqu'à ce que quelque chose soit modifié dans l'espace partagé!
Pour donner un autre exemple, Mercurial utilise la copie sur écriture pour faire du clonage de référentiels locaux une opération vraiment "bon marché".
Le principe est le même que pour les autres exemples, sauf que vous parlez de fichiers physiques au lieu d'objets en mémoire. Au départ, un clone n'est pas un duplicata mais un lien dur vers l'original. Lorsque vous modifiez des fichiers dans le clone, des copies sont écrites pour représenter la nouvelle version.
J'ai trouvé ce bon article sur zval en PHP, qui mentionnait aussi COW:
Copy On Write (abrégé en «COW») est une astuce conçue pour économiser de la mémoire. Il est utilisé plus généralement en génie logiciel. Cela signifie que PHP copiera la mémoire (ou allouera une nouvelle région mémoire) lorsque vous écrivez sur un symbole, si celui-ci pointait déjà vers un zval.
Un bon exemple est Git, qui utilise une stratégie pour stocker des objets blob. Pourquoi utilise-t-il des hachages? En partie parce que ceux-ci sont plus faciles à exécuter sur les diffs, mais aussi parce que cela simplifie l'optimisation d'une stratégie COW. Lorsque vous effectuez un nouveau commit avec peu de modifications de fichiers, la grande majorité des objets et des arbres ne changeront pas. Par conséquent, le commit, à travers divers pointeurs faits de hachages, fera référence à un groupe d'objets qui existent déjà, rendant l'espace de stockage nécessaire pour stocker l'historique entier beaucoup plus petit.
Voici une implémentation Python de copie sur écriture (COW) utilisant le modèle de conception décorateur . Une référence à un Value
objet immuable est détenue par un CowValue
objet mutable (le décorateur). L' CowValue
objet transmet toutes les demandes de lecture à l' Value
objet immuable et intercepte toutes les demandes d'écriture en créant un nouvel Value
objet immuable avec l'état correct. L' CowValue
objet doit être copié superficiellement entre les variables pour permettre le partage de l' Value
objet.
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)