Sao chép trên văn bản là gì?


133

Tôi muốn biết copy-on-write là gì và nó được dùng để làm gì? Thuật ngữ 'mảng sao chép trên ghi' được nhắc đến nhiều lần trong các hướng dẫn về JDK của Sun nhưng tôi không hiểu ý nghĩa của nó.

Câu trả lời:


155

Tôi sẽ viết lên lời giải thích của riêng tôi nhưng bài viết trên Wikipedia này đã tóm tắt khá nhiều.

Đây là khái niệm cơ bản:

Copy-on-write (đôi khi được gọi là "COW") là một chiến lược tối ưu hóa được sử dụng trong lập trình máy tính. Ý tưởng cơ bản là nếu nhiều người gọi yêu cầu các tài nguyên ban đầu không thể phân biệt được, bạn có thể cung cấp cho họ các con trỏ tới cùng một tài nguyên. Chức năng này có thể được duy trì cho đến khi người gọi cố gắng sửa đổi "bản sao" tài nguyên của mình, tại đó, một bản sao riêng thực sự được tạo để ngăn những thay đổi hiển thị cho mọi người khác. Tất cả điều này xảy ra trong suốt cho người gọi. Ưu điểm chính là nếu người gọi không bao giờ thực hiện bất kỳ sửa đổi nào, thì không cần phải sao chép riêng tư.

Ngoài ra đây là một ứng dụng sử dụng chung của COW:

Khái niệm COW cũng được sử dụng để bảo trì ảnh chụp nhanh tức thì trên các máy chủ cơ sở dữ liệu như Microsoft SQL Server 2005. Ảnh chụp nhanh tức thì giữ chế độ xem tĩnh của cơ sở dữ liệu bằng cách lưu trữ bản sao dữ liệu sửa đổi trước khi cập nhật dữ liệu. Ảnh chụp nhanh tức thì được sử dụng để kiểm tra sử dụng hoặc báo cáo phụ thuộc vào thời điểm và không nên được sử dụng để thay thế bản sao lưu.


bất cứ điều gì một mảng thông thường được sử dụng cho ... tuy nhiên, trong một số trường hợp, loại chiến lược này mang lại kết quả tối ưu hơn.
Andrew Flanagan

3
@hhafez: Linux sử dụng nó khi nó sử dụng clone()để thực hiện fork()- bộ nhớ của tiến trình cha mẹ được COWed cho đứa trẻ.
Kerrek SB

@hhafez Một số hệ thống tập tin sử dụng CoW, ví dụ: BTRFS .
Lão máu

Đây có phải là cách SandboxIE hoạt động? khi một chương trình hộp cát muốn ghi đè lên một cái gì đó, hộp cát sẽ chặn hoạt động của hệ thống tệp và sao chép tệp vào thư mục hộp cát và để chương trình ghi vào tệp hộp cát thay vì tệp gốc. Cái đó có tên là Copy on write không?
Ronnie Matthews

Làm thế nào để hợp nhất xảy ra cuối cùng? Nếu có N bản sao, bản nào cuối cùng được lưu trên đĩa nói?
SimpleGuy

59

"Sao chép trên ghi" có nghĩa là ít nhiều có vẻ như: mọi người đều có một bản sao được chia sẻ của cùng một dữ liệu cho đến khi nó được viết và sau đó một bản sao được tạo. Thông thường, copy-on-write được sử dụng để giải quyết các loại vấn đề tương tranh. Trong ZFS , ví dụ, các khối dữ liệu trên đĩa được phân bổ sao chép khi ghi; miễn là không có thay đổi, bạn giữ nguyên các khối ban đầu; một thay đổi chỉ thay đổi các khối bị ảnh hưởng. Điều này có nghĩa là số lượng tối thiểu của các khối mới được phân bổ.

Những thay đổi này cũng thường được thực hiện để giao dịch , nghĩa là chúng có các thuộc tính ACID . Điều này giúp loại bỏ một số vấn đề tương tranh, bởi vì sau đó bạn được đảm bảo rằng tất cả các cập nhật là nguyên tử.


1
Nếu bạn thực hiện thay đổi, làm thế nào để người khác nhận được thông báo về bản sao mới của bạn? Họ sẽ không nhìn thấy dữ liệu sai.
bột366

12
@ Powder366 - Không họ sẽ không nhìn thấy dữ liệu sai bởi vì khi bạn thực hiện thay đổi đó là khi một bản sao thực sự được thực hiện. Ví dụ, bạn có một khối dữ liệu được gọi A. Quy trình 1, 2, 3, 4từng muốn thực hiện một bản sao của nó và bắt đầu đọc nó, trong một "Copy trên ghi" hệ thống không có gì được sao chép nhưng mọi thứ vẫn đang đọc A. Bây giờ quá trình 3muốn thực hiện thay đổi đối với bản sao của nó A, quy trình 3thực sự sẽ tạo một bản sao Avà tạo một khối dữ liệu mới được gọi B. Quy trình 1, 2, 4vẫn đọc khối Aquá trình 3bây giờ đã đọc B.
Puddler

1
@Puddler điều gì sẽ xảy ra nếu những thay đổi được thực hiện trong 'A'. Tất cả các quy trình sẽ được đọc thông tin cập nhật hay cũ?
Nhà phát triển

3
@ Nhà phát triển: Bất kỳ quá trình nào đang thực hiện thay đổi Asẽ tạo ra một bản sao mới. Nếu bạn đang hỏi điều gì xảy ra nếu một quá trình hoàn toàn mới xuất hiện và thay đổi Athì lời giải thích của tôi không thực sự đi sâu vào chi tiết cho điều đó. Đó sẽ là triển khai cụ thể và yêu cầu kiến ​​thức về cách bạn muốn phần còn lại của triển khai hoạt động, chẳng hạn như tệp \ khóa dữ liệu, v.v.
Puddler

10

Tôi sẽ không lặp lại câu trả lời tương tự trên Copy-on-Write. Tôi nghĩ câu trả lời của Andrewcâu trả lời của Charlie đã làm cho nó rất rõ ràng. Tôi sẽ cho bạn một ví dụ từ thế giới HĐH, chỉ đề cập đến việc khái niệm này được sử dụng rộng rãi như thế nào.

Chúng ta có thể sử dụng fork()hoặc vfork()để tạo ra một quy trình mới. vfork tuân theo khái niệm copy-on-write. Ví dụ, quy trình con được tạo bởi vfork sẽ chia sẻ dữ liệu và phân đoạn mã với quy trình cha. Điều này tăng tốc thời gian rèn. Dự kiến ​​sẽ sử dụng vfork nếu bạn đang thực hiện exec theo sau là vfork. Vì vậy, vfork sẽ tạo tiến trình con sẽ chia sẻ dữ liệu và phân đoạn mã với cha mẹ của nó, nhưng khi chúng ta gọi exec, nó sẽ tải lên hình ảnh của một tệp thực thi mới trong không gian địa chỉ của tiến trình con.


3
"Vfork tuân theo khái niệm copy-on-write". Hãy xem xét thay đổi dòng này. vforkKHÔNG sử dụng COW. Trong thực tế nếu đứa trẻ viết một cái gì đó, nó có thể dẫn đến hành vi không xác định và không sao chép các trang !! Trong thực tế, bạn có thể nói cách khác vòng là hơi đúng. COW hoạt động như vforkcho đến khi một cái gì đó được sửa đổi trong không gian chia sẻ!
Pavan Manjunath

Hoàn toàn đồng ý với Pavan. Xóa các dòng "vfork tuân theo khái niệm copy-on-write". Bây giờ, COW được sử dụng trong fork để tối ưu hóa, do đó, nó hoạt động như vfork và không tạo bản sao dữ liệu của cha mẹ cho quá trình con (nếu chúng ta chỉ gọi exec * in child)
Shekhar Kumar

7

Chỉ để cung cấp một ví dụ khác, Mercurial sử dụng copy-on-write để biến các kho lưu trữ cục bộ thành một hoạt động thực sự "rẻ tiền".

Nguyên tắc này giống như các ví dụ khác, ngoại trừ việc bạn đang nói về các tệp vật lý thay vì các đối tượng trong bộ nhớ. Ban đầu, một bản sao không phải là một bản sao mà là một liên kết cứng với bản gốc. Khi bạn thay đổi tệp trong bản sao, các bản sao được viết để thể hiện phiên bản mới.


2

Tôi tìm thấy này bài viết tốt về zval trong PHP, mà đề cập COW quá:

Copy On Write (viết tắt là 'COW') là một mẹo được thiết kế để tiết kiệm bộ nhớ. Nó được sử dụng phổ biến hơn trong công nghệ phần mềm. Điều đó có nghĩa là PHP sẽ sao chép bộ nhớ (hoặc phân bổ vùng bộ nhớ mới) khi bạn viết vào một ký hiệu, nếu cái này đã được trỏ đến một giá trị zval.


0

Nó cũng được sử dụng trong Ruby 'Enterprise Edition' như một cách tiết kiệm bộ nhớ gọn gàng.


2
Tôi không nghĩ anh ấy có nghĩa là "được sử dụng" theo nghĩa đó.
spydon

0

Một ví dụ điển hình là Git, sử dụng chiến lược để lưu trữ các đốm màu. Tại sao nó sử dụng băm? Một phần vì những thứ này dễ thực hiện khác hơn, nhưng cũng vì nó đơn giản hơn để tối ưu hóa chiến lược COW. Khi bạn thực hiện một cam kết mới với một vài tệp thay đổi, phần lớn các đối tượng và cây sẽ không thay đổi. Do đó, cam kết, sẽ thông qua các con trỏ khác nhau được tạo bởi các giá trị băm tham chiếu một loạt các đối tượng đã tồn tại, làm cho không gian lưu trữ cần thiết để lưu trữ toàn bộ lịch sử nhỏ hơn nhiều.


0

Đó là một khái niệm bảo vệ bộ nhớ. Trong trình biên dịch này tạo thêm bản sao để sửa đổi dữ liệu ở trẻ và dữ liệu cập nhật này không phản ánh trong dữ liệu của cha mẹ.


0

Đây là một triển khai Python sao chép trên ghi (COW) bằng cách sử dụng mẫu thiết kế trang trí . Một tham chiếu đến một Valueđối tượng bất biến được giữ bởi một CowValueđối tượng có thể thay đổi (người trang trí). Đối CowValuetượng chuyển tiếp tất cả các yêu cầu đọc đến Valueđối tượng bất biến và chặn tất cả các yêu cầu ghi bằng cách tạo một Valueđối tượng bất biến mới với trạng thái chính xác. Đối CowValuetượng phải được sao chép nông giữa các biến để cho phép chia sẻ Valueđối tượng.

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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.