Що таке копіювання під час запису?


134

Мені хотілося б знати, що таке копіювання при записі і для чого воно використовується? Термін "масив копію на запис" згадується кілька разів у навчальних посібниках Sun JDK, але я не розумів, що це означає.

Відповіді:


156

Я збирався написати своє власне пояснення, але ця стаття у Вікіпедії дуже резюмує це.

Ось основна концепція:

Copy-on-write (іноді його називають "COW") - це стратегія оптимізації, що використовується в комп'ютерному програмуванні. Основна ідея полягає в тому, що якщо кілька абонентів запитують ресурси, які спочатку не відрізняються, ви можете надати їм покажчики на один і той же ресурс. Цю функцію можна підтримувати, поки абонент не спробує змінити свою "копію" ресурсу, і в цей момент буде створена справжня приватна копія, щоб запобігти тому, щоб зміни стали видимими для всіх інших. Все це відбувається прозоро з абонентами. Основна перевага полягає в тому, що якщо абонент ніколи не вносить будь-яких модифікацій, приватна копія ніколи не створюватиметься.

Також тут представлено загальне застосування коров’ячої сировини:

Концепція COW також використовується для підтримки миттєвого знімка на серверах баз даних, таких як Microsoft SQL Server 2005. Миттєві знімки зберігають статичний вигляд бази даних, зберігаючи попередньо модифіковану копію даних при оновленні нижчих даних. Миттєві знімки використовуються для тестування використання або звітів, що залежать від моменту, і не повинні використовуватися для заміни резервних копій.


все, для чого використовується звичайний масив ... проте в деяких ситуаціях такий тип стратегії призводить до більш оптимізованих результатів.
Ендрю Фланаган

3
@hhafez: Linux використовує його, коли використовує clone()для реалізації fork()- пам’ять батьківського процесу є COWed для дитини.
Керрек СБ

@hhafez Деякі файлові системи використовують CoW, наприклад, BTRFS .
Геремія

Так працює SandboxIE? коли програма з пісочницею хоче перезаписати щось, пісочниця перехоплює операцію файлової системи та копіює файл у папку пісочниці та дозволяє програмі записувати у файл із пісочним файлом замість оригіналу. Це називається Copy on write?
Ронні Меттьюз

Як в результаті відбувається злиття? Якщо є N копій, яку зрештою зберігати, щоб зберегти на скажімо диску?
SimpleGuy

59

"Копіювати при записі" означає більш-менш те, що це звучить: кожен має одну спільну копію одних і тих же даних, поки не буде записано , а потім буде зроблена копія. Зазвичай копіювання при записі використовується для вирішення різновидів проблем. Наприклад, у ZFS блокам даних на диску виділяється копіювання під час запису; доки не буде змін, ви зберігаєте оригінальні блоки; зміна змінила лише постраждалі блоки. Це означає, що мінімальна кількість нових блоків виділяється.

Ці зміни також зазвичай реалізуються як транзакційні , тобто вони мають властивості кислотної кислоти . Це усуває деякі проблеми одночасності, оскільки тоді ви гарантуєте, що всі оновлення є атомними.


1
Якщо ви внесете зміни, як інший отримує повідомлення про вашу нову копію? Чи не бачили вони неправильні дані.
порошок666

12
@ powder366 - Ні, вони не бачать помилкових даних, оскільки коли ви вносите зміни, саме тоді робиться копія. Наприклад, у вас є блок даних, який називається A. Процес 1, 2, 3, 4кожен хоче зробити копію і почати читати його, в «копіюванні при записи» система нічого не копіюється поки все ще читають A. Тепер процес 3хоче змінити його копію A, процес 3тепер фактично зробить копію Aта створить новий блок даних, який називається B. Процес 1, 2, 4все ще читає блок - Aпроцес 3в даний час читання B.
Калюжа

1
@Puddler, що станеться, якщо зміни будуть внесені в "A". Усі процеси будуть читати оновлену інформацію чи стару?
розробник

3
@Developer: Що б будь-який процес вносив зміни, Aслід створити нову копію. Якщо ви запитуєте, що відбувається, якщо відбудеться і зміниться абсолютно новий процес, Aто моє пояснення насправді не надто детально для цього. Це буде специфічно для впровадження та вимагає знань про те, як ви хочете, щоб решта імплементації працювала, наприклад, файл \ блокування даних тощо.
Puddler

10

Я не повторюю ту саму відповідь у Copy-on-Write. Я думаю , що відповідь Ендрю і відповідь Чарлі вже дуже ясно. Я надам вам приклад зі світу ОС, просто зазначу, наскільки широко використовується ця концепція.

Ми можемо використовувати fork()або vfork()створити новий процес. vfork дотримується концепції копіювання на запис. Наприклад, дочірній процес, створений vfork, поділиться сегментом даних та коду з батьківським процесом. Це прискорює час розщеплення. Очікується використовувати vfork, якщо ви виконуєте exec, а потім vfork. Таким чином, vfork створить дочірній процес, який буде обмінюватися даними та кодовим сегментом зі своїм батьківським, але коли ми зателефонуємо до exec, він завантажить зображення нового виконуваного файлу в адресний простір дочірнього процесу.


3
"vfork дотримується концепції копіювання на запис". Подумайте про зміну цього рядка. vforkНЕ використовує COW. Насправді, якщо дитина щось пише, це може призвести до невизначеної поведінки, а не до копіювання сторінок !! Насправді, можна сказати, навпаки, дещо правда. COW діє так, vforkпоки щось не зміниться в спільному просторі!
Pavan Manjunath

Повністю згоден з Паваном. Видаліть рядки "vfork слід за принципом" копіювати на запис ". Зараз дні, COW використовується у вилці як оптимізація, щоб він діяв як vfork і не робив копії батьківських даних для дочірнього процесу (якщо ми називаємо лише exec * у дитини)
Shekhar Kumar

7

Просто для надання іншого прикладу, Mercurial використовує функцію копіювання на запис, щоб зробити клонування локальних сховищ дійсно «дешевою» операцією.

Принцип такий самий, як і в інших прикладах, за винятком того, що ви говорите про фізичні файли замість об'єктів у пам'яті. Спочатку клон - це не дублікат, а тверда посилання на оригінал. Під час зміни файлів у клоні записуються копії, які представляють нову версію.


2

Я знайшов цю хорошу статтю про zval в PHP, в якій згадується і COW:

Copy On Write (скорочено "COW") - фокус, призначений для економії пам'яті. Він використовується більш загально в інженерії програмного забезпечення. Це означає, що PHP буде копіювати пам'ять (або виділяти нову область пам'яті), коли ви пишете на символ, якщо ця вже вказувала на zval.


0

Він також використовується в Ruby 'Enterprise Edition' як акуратний спосіб збереження пам'яті.


2
Я не думаю, що він мав на увазі "використаний для" в цьому сенсі.
шпидон

0

Хороший приклад - Git, який використовує стратегію зберігання крапок. Чому він використовує хеші? Частково через те, що це легше виконати, це відрізняється, а також тому, що спрощує оптимізацію стратегії роботи з коровами. Коли ви робите нову фіксацію з кількома файлами змін, переважна більшість об'єктів і дерева не змінюватимуться. Тому фіксація, через різні покажчики, зроблені з хешей, посилається на купу об'єктів, які вже існують, завдяки чому місця для зберігання, необхідні для зберігання всієї історії, значно менше.


0

Це концепція захисту пам'яті. У цьому компіляторі створюється додаткова копія для зміни даних у дочірніх даних, і ці оновлені дані не відображаються в даних батьків.


0

Ось після цього - реалізація Python копіювання за записом (COW) за допомогою шаблону дизайну декоратора . Посилання на незмінний Valueпредмет тримається мутаторомCowValue предметом, що (декоратором). CowValueОб'єкт передає всі запити на читання до постійного Valueоб'єкта і перехоплює всі запити на запис, створюючи новий незмінний Valueоб'єкт з правильним станом. CowValueОб'єкт повинен бути неглибокий копіюватися між змінними , щоб дозволити спільне використання Valueоб'єкта.

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.