Respostas:
Eu ia escrever minha própria explicação, mas este artigo da Wikipedia resume bastante.
Aqui está o conceito básico:
A cópia na gravação (às vezes chamada de "COW") é uma estratégia de otimização usada na programação de computadores. A idéia fundamental é que, se vários chamadores solicitarem recursos inicialmente indistinguíveis, você poderá fornecer indicadores para o mesmo recurso. Essa função pode ser mantida até que um chamador tente modificar sua "cópia" do recurso, quando uma cópia privada verdadeira é criada para impedir que as alterações fiquem visíveis para todos os outros. Tudo isso acontece de forma transparente para os chamadores. A principal vantagem é que, se um chamador nunca fizer nenhuma modificação, nenhuma cópia privada será criada.
Também aqui está uma aplicação de um uso comum do COW:
O conceito COW também é usado na manutenção de instantâneos instantâneos em servidores de banco de dados como o Microsoft SQL Server 2005. Os instantâneos instantâneos preservam uma visão estática de um banco de dados, armazenando uma cópia de pré-modificação dos dados quando os dados subjacentes são atualizados. Instantâneos instantâneos são usados para testes de uso ou relatórios dependentes de momento e não devem ser usados para substituir backups.
clone()implementa fork()- a memória do processo pai é COW para a criança.
"Copiar na gravação" significa mais ou menos o que parece: todos têm uma única cópia compartilhada dos mesmos dados até que sejam gravados e, em seguida, uma cópia é feita. Geralmente, a cópia na gravação é usada para resolver os tipos de problemas de simultaneidade. No ZFS , por exemplo, os blocos de dados no disco são alocados na cópia; contanto que não haja alterações, você mantém os blocos originais; uma mudança alterou apenas os blocos afetados. Isso significa que o número mínimo de novos blocos é alocado.
Essas alterações também são geralmente implementadas para serem transacionais , ou seja, elas têm as propriedades ACID . Isso elimina alguns problemas de simultaneidade, porque você garante que todas as atualizações são atômicas.
A. Processo 1, 2, 3, 4cada um quer fazer uma cópia do mesmo e começar a lê-lo, em uma "cópia na escrita" Sistema nada é copiado mas tudo ainda está lendo A. Agora, o processo 3deseja alterar sua cópia A, 3agora o processo efetua uma cópia Ae cria um novo bloco de dados chamado B. Processo 1, 2, 4ainda está lendo bloco Aprocesso 3está agora lendo B.
Adeve estar criando uma nova cópia. Se você está perguntando o que acontece se um processo totalmente novo surgir e mudar A, minha explicação não entra em detalhes suficientes para isso. Isso seria implementação específica e exigem conhecimento sobre como você deseja que o resto da aplicação ao trabalho, tais como arquivo \ bloqueio de dados, etc.
Não repetirei a mesma resposta em Copy-on-Write. Acho que a resposta de Andrew e a de Charlie já deixaram muito claro. Vou dar um exemplo do mundo do SO, apenas para mencionar o quão amplamente esse conceito é usado.
Podemos usar fork()ou vfork()criar um novo processo. O vfork segue o conceito de cópia na gravação. Por exemplo, o processo filho criado pelo vfork compartilhará o segmento de dados e código com o processo pai. Isso acelera o tempo de bifurcação. Espera-se usar o vfork se você estiver executando exec seguido pelo vfork. Portanto, o vfork criará o processo filho que compartilhará os dados e o segmento de código com seu pai, mas quando chamamos exec, ele carregará a imagem de um novo executável no espaço de endereço do processo filho.
vforkNÃO usa VACA. De fato, se a criança escreve algo, pode resultar em comportamento indefinido e não copiar páginas! De fato, você pode dizer que o contrário é verdade. COW age como vforkaté que algo seja modificado no espaço compartilhado!
Apenas para dar outro exemplo, o Mercurial usa a cópia na gravação para tornar a clonagem de repositórios locais uma operação realmente "barata".
O princípio é o mesmo dos outros exemplos, exceto que você está falando sobre arquivos físicos em vez de objetos na memória. Inicialmente, um clone não é uma duplicata, mas um vínculo físico com o original. Conforme você altera os arquivos no clone, as cópias são gravadas para representar a nova versão.
Encontrei este bom artigo sobre o zval no PHP, que também mencionou o COW:
Copy On Write (abreviado como 'COW') é um truque projetado para economizar memória. É usado de maneira mais geral na engenharia de software. Isso significa que o PHP copiará a memória (ou alocará nova região de memória) quando você escrever em um símbolo, se este já estiver apontando para um zval.
Também é usado no Ruby 'Enterprise Edition' como uma maneira elegante de economizar memória.
Um bom exemplo é o Git, que usa uma estratégia para armazenar blobs. Por que ele usa hashes? Em parte porque essas são mais fáceis de executar, mas também porque simplifica a otimização de uma estratégia de COW. Quando você faz um novo commit com poucos arquivos, a grande maioria dos objetos e as árvores não são alteradas. Portanto, o commit, através de vários ponteiros feitos de hashes, fará referência a um monte de objetos que já existem, tornando o espaço de armazenamento necessário para armazenar todo o histórico muito menor.
A seguir, é apresentada uma implementação Python de copiar-em-gravar (COW), usando o padrão de design do decorador . Uma referência a um Valueobjeto imutável é mantida por um CowValueobjeto mutável (o decorador). O CowValueobjeto encaminha todas as solicitações de leitura para o Valueobjeto imutável e intercepta todas as solicitações de gravação criando um novo Valueobjeto imutável com o estado correto. O CowValueobjeto deve ser copiado superficialmente entre as variáveis para permitir o compartilhamento do Valueobjeto.
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)