Yanıtlar:
Kendi açıklamamı yazacaktım ama bu Wikipedia makalesi bunu hemen hemen özetliyor.
İşte temel kavram:
Yazma üzerine kopyalama (bazen "COW" olarak anılır), bilgisayar programlamasında kullanılan bir optimizasyon stratejisidir. Temel fikir, eğer birden çok arayan başlangıçta ayırt edilemeyen kaynaklar isterse, onlara aynı kaynağa işaretçiler verebilirsiniz. Bu işlev, arayan kişi kaynağın "kopyasını" değiştirmeye çalışıncaya kadar sürdürülebilir, bu noktada değişikliklerin diğer herkes tarafından görülebilir olmasını önlemek için gerçek bir özel kopya oluşturulur. Tüm bunlar arayanlara şeffaf bir şekilde gerçekleşir. Birincil avantaj, arayan kişi hiçbir zaman değişiklik yapmazsa, özel bir kopya oluşturulmasına gerek olmamasıdır.
Ayrıca burada COW'nin yaygın kullanımının bir uygulaması:
COW kavramı, Microsoft SQL Server 2005 gibi veritabanı sunucularında anlık anlık görüntünün bakımında da kullanılır. Anlık anlık görüntüler, alt katman verileri güncellendiğinde verilerin bir ön değişiklik kopyasını depolayarak bir veritabanının statik görünümünü korur. Anlık anlık görüntüler, kullanımları veya ana bağlı raporları test etmek için kullanılır ve yedeklerin yerini almak için kullanılmamalıdır.
clone()
uygulamak için kullandığında onu kullanır fork()
- ana sürecin hafızası çocuk için COW'dur.
"Yazılırken kopyala", aşağı yukarı göründüğü anlamına gelir: herkes yazılana kadar aynı verilerin tek bir paylaşılan kopyasına sahiptir ve ardından bir kopya yapılır. Genellikle, eşzamanlılık gibi sorunları çözmek için yazma üzerine kopyalama kullanılır. Örneğin ZFS'de , disk üzerindeki veri blokları yazma üzerine kopyalama olarak tahsis edilir; değişiklik olmadığı sürece, orijinal blokları korursunuz; bir değişiklik yalnızca etkilenen blokları değiştirdi. Bu, minimum sayıda yeni blok tahsis edildiği anlamına gelir.
Bu değişiklikler ayrıca genellikle işlemsel olarak uygulanır , yani ACID özelliklerine sahiptirler. Bu, bazı eşzamanlılık sorunlarını ortadan kaldırır, çünkü o zaman tüm güncellemelerin atomik olduğu garanti edilir.
A
. Süreç 1
, 2
, 3
, 4
her Talep bir kopyasını yapmak ve sistem hiçbir şey kopyalanır henüz her şey hala okuma "yazma sırasında kopyala" Bir de, okumaya başlamak için A
. Şimdi işlem , 3
kopyasında bir değişiklik yapmak istiyor A
, işlem 3
şimdi aslında bir kopyasını yapacak A
ve adı verilen yeni bir veri bloğu oluşturacak B
. Süreç 1
, 2
, 4
hala blok okuduğunuz A
süreci 3
şimdi okuyor B
.
A
yeni bir kopya oluşturmalı. Tamamen yeni bir süreç gelir ve değişirse ne olacağını soruyorsanız, A
açıklamam bunun için yeterince ayrıntıya girmiyor. Bu, uygulamaya özgü olacaktır ve uygulamanın geri kalanının nasıl çalışmasını istediğiniz hakkında bilgi gerektirir, örneğin dosya \ veri kilitleme vb.
Aynı cevabı Yazılırken Kopyala'da tekrar etmeyeceğim. Sanırım Andrew'un cevabı ve Charlie'nin cevabı bunu çok netleştirdi. Size işletim sistemi dünyasından bir örnek vereceğim, sadece bu kavramın ne kadar yaygın kullanıldığını belirtmek için.
Yeni bir süreç oluşturmak için fork()
veya kullanabiliriz vfork()
. vfork, yazma üzerine kopyalama kavramını izler. Örneğin, vfork tarafından oluşturulan alt süreç, verileri ve kod segmentini üst süreçle paylaşır. Bu, çatallanma süresini hızlandırır. Eğer exec ardından vfork yapıyorsanız, vfork kullanmanız beklenir. Dolayısıyla vfork, veriyi ve kod segmentini ebeveyniyle paylaşacak çocuk süreci yaratacak, ancak exec'yi çağırdığımızda, alt sürecin adres alanına yeni bir yürütülebilir dosyanın görüntüsünü yükleyecektir.
vfork
COW KULLANMAZ. Aslında, çocuk bir şey yazarsa, bu tanımsız davranışlara neden olabilir ve sayfaların kopyalanmasına neden olmaz !! Aslında, tam tersi bir şekilde doğru diyebilirsiniz. COW vfork
, paylaşılan alanda bir şey değiştirilene kadar davranır !
Başka bir örnek vermek gerekirse, Mercurial yerel depoları klonlamayı gerçekten "ucuz" bir işlem haline getirmek için yazarken kopyala özelliğini kullanıyor .
İlke, bellekteki nesneler yerine fiziksel dosyalardan bahsetmeniz dışında diğer örneklerle aynıdır. Başlangıçta, bir klon bir kopya değil , orijinal ile sabit bir bağlantıdır . Klondaki dosyaları değiştirdiğinizde, kopyalar yeni sürümü temsil edecek şekilde yazılır.
PHP'de zval hakkında COW'dan da bahseden bu güzel makaleyi buldum :
Yazarken Kopyala ('COW' olarak kısaltılır) hafızadan tasarruf etmek için tasarlanmış bir numaradır. Daha genel olarak yazılım mühendisliğinde kullanılır. Bu, bir sembole yazarken PHP'nin belleği kopyalayacağı (veya yeni bellek bölgesi tahsis edeceği) anlamına gelir, eğer bu zaten bir zval'i gösteriyorsa.
İyi bir örnek, blobları depolamak için bir strateji kullanan Git'tir. Neden karma kullanır? Kısmen bunların gerçekleştirilmesi daha kolay olduğu için, ancak aynı zamanda bir COW stratejisini optimize etmeyi kolaylaştırdığı için. Birkaç dosya değişikliği ile yeni bir işlem yaptığınızda, nesnelerin ve ağaçların büyük çoğunluğu değişmeyecektir. Bu nedenle commit, hashlerden oluşan çeşitli işaretçiler aracılığıyla zaten var olan bir nesneye referans verecek ve tüm geçmişi depolamak için gereken depolama alanını çok daha küçük hale getirecektir.
İşte bundan sonra, dekoratör tasarım modelini kullanan bir yazma üzerine kopyalama (COW) Python uygulaması . Değişmez bir Value
nesneye yapılan gönderme, değiştirilebilir bir CowValue
nesne (dekoratör) tarafından tutulur . CowValue
Nesne ileri bütün değişmez yapılan okuma istekleri Value
yeni değişmez oluşturarak nesne ve yakaladığını tüm yazma isteklerini Value
doğru devletle nesneyi. CowValue
Nesne sığ paylaşılmasına izin değişkenler arasında kopyalanması gerekir Value
nesne.
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)