Risposte:
Stavo per scrivere la mia spiegazione, ma questo articolo di Wikipedia lo riassume praticamente.
Ecco il concetto di base:
Copy-on-write (a volte indicato come "COW") è una strategia di ottimizzazione utilizzata nella programmazione informatica. L'idea fondamentale è che se più chiamanti chiedono risorse che inizialmente sono indistinguibili, è possibile fornire loro puntatori alla stessa risorsa. Questa funzione può essere mantenuta fino a quando un chiamante non tenta di modificare la sua "copia" della risorsa, a quel punto viene creata una vera copia privata per impedire che le modifiche diventino visibili a tutti gli altri. Tutto ciò accade in modo trasparente ai chiamanti. Il vantaggio principale è che se un chiamante non apporta mai alcuna modifica, non è mai necessario creare una copia privata.
Anche qui è un'applicazione di un uso comune di COW:
Il concetto di COW viene utilizzato anche per la manutenzione di istantanee istantanee su server di database come Microsoft SQL Server 2005. Le istantanee istantanee preservano una vista statica di un database memorizzando una copia di pre-modifica dei dati durante l'aggiornamento dei dati di base. Le istantanee sono utilizzate per test di utilizzo o report dipendenti dal momento e non devono essere utilizzate per sostituire i backup.
clone()
per implementare fork()
- la memoria del processo genitore è COWed per il bambino.
"Copia su scrittura" significa più o meno quello che sembra: ognuno ha una singola copia condivisa degli stessi dati fino a quando non viene scritta , e quindi viene fatta una copia. Di solito, la copia su scrittura viene utilizzata per risolvere i problemi di concorrenza. In ZFS , ad esempio, i blocchi di dati su disco sono allocati copia su scrittura; fintanto che non ci sono modifiche, si mantengono i blocchi originali; una modifica ha modificato solo i blocchi interessati. Ciò significa che viene assegnato il numero minimo di nuovi blocchi.
Questi cambiamenti sono anche generalmente implementati essere transazionale , cioè, hanno le ACID proprietà. Questo elimina alcuni problemi di concorrenza, perché in questo caso sei sicuro che tutti gli aggiornamenti sono atomici.
A
. Processo 1
, 2
, 3
, 4
ogni voglia di fare una copia di esso e iniziare a leggerlo, in una "copy on write" sistema di nulla viene copiato eppure tutto è ancora leggendo A
. Ora il processo 3
vuole apportare una modifica alla sua copia A
, 3
ora il processo effettivamente eseguirà una copia A
e creerà un nuovo blocco di dati chiamato B
. Processo 1
, 2
, 4
stanno ancora leggendo blocco A
processo 3
è ora di lettura B
.
A
dovrebbe creare una nuova copia. Se stai chiedendo cosa succede se un processo completamente nuovo si presenta e cambia, A
allora la mia spiegazione non è abbastanza dettagliata. Sarebbe specifico per l'implementazione e richiederebbe la conoscenza di come vuoi che funzioni il resto dell'implementazione, come file \ data
Non ripeterò la stessa risposta su Copia su scrittura. Penso che la risposta di Andrew e quella di Charlie abbiano già reso molto chiaro. Vi farò un esempio dal mondo dei sistemi operativi, solo per menzionare quanto ampiamente viene usato questo concetto.
Possiamo usare fork()
o vfork()
per creare un nuovo processo. vfork segue il concetto di copia su scrittura. Ad esempio, il processo figlio creato da vfork condividerà i dati e il segmento di codice con il processo padre. Questo accelera il tempo di forking. Si prevede di utilizzare vfork se si esegue exec seguito da vfork. Quindi vfork creerà il processo figlio che condividerà i dati e il segmento di codice con il suo genitore ma quando chiamiamo exec, caricherà l'immagine di un nuovo eseguibile nello spazio degli indirizzi del processo figlio.
vfork
NON usa MUCCA. Infatti se il bambino scrive qualcosa, può comportare un comportamento indefinito e non copiare le pagine !! In effetti, puoi dire che è vero il contrario. COW si comporta come vfork
fino a quando qualcosa non viene modificato nello spazio condiviso!
Giusto per fornire un altro esempio, Mercurial utilizza la funzione di copia su scrittura per rendere la clonazione dei repository locali un'operazione davvero "economica".
Il principio è lo stesso degli altri esempi, tranne per il fatto che stai parlando di file fisici anziché di oggetti in memoria. Inizialmente, un clone non è un duplicato ma un collegamento reale all'originale. Quando si modificano i file nel clone, le copie vengono scritte per rappresentare la nuova versione.
Ho trovato questo buon articolo su zval in PHP, che menzionava anche COW:
Copy On Write (abbreviato in 'COW') è un trucco progettato per risparmiare memoria. È usato più in generale nell'ingegneria del software. Significa che PHP copierà la memoria (o allocherà una nuova area di memoria) quando si scrive su un simbolo, se questo puntava già a uno zval.
Un buon esempio è Git, che utilizza una strategia per archiviare i BLOB. Perché usa gli hash? In parte perché questi sono più facili da eseguire su differenze, ma anche perché semplifica l'ottimizzazione di una strategia COW. Quando si effettua un nuovo commit con poche modifiche ai file, la stragrande maggioranza degli oggetti e degli alberi non cambierà. Pertanto il commit, attraverso vari puntatori fatti di hash, farà riferimento a un gruppo di oggetti già esistenti, rendendo lo spazio di archiviazione richiesto per memorizzare l'intera storia molto più piccola.
Qui di seguito è una implementazione Python copia-su-scrittura (COW) utilizzando il modello di progettazione del decoratore . Un riferimento a un Value
oggetto immutabile è trattenuto da un CowValue
oggetto mutabile (il decoratore). L' CowValue
oggetto inoltra tutte le richieste di lettura Value
all'oggetto immutabile e intercetta tutte le richieste di scrittura creando un nuovo Value
oggetto immutabile con lo stato corretto. L' CowValue
oggetto deve essere copiato in modo superficiale tra le variabili per consentire la condivisione Value
dell'oggetto.
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)