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
, 4
cada 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 3
deseja alterar sua cópia A
, 3
agora o processo efetua uma cópia A
e cria um novo bloco de dados chamado B
. Processo 1
, 2
, 4
ainda está lendo bloco A
processo 3
está agora lendo B
.
A
deve 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.
vfork
NÃ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 vfork
até 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 Value
objeto imutável é mantida por um CowValue
objeto mutável (o decorador). O CowValue
objeto encaminha todas as solicitações de leitura para o Value
objeto imutável e intercepta todas as solicitações de gravação criando um novo Value
objeto imutável com o estado correto. O CowValue
objeto deve ser copiado superficialmente entre as variáveis para permitir o compartilhamento do Value
objeto.
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)