อยากทราบว่า copy-on-write คืออะไรและใช้ทำอะไร? คำว่า 'copy-on-write array' ถูกกล่าวถึงหลายครั้งในบทแนะนำ Sun JDK แต่ฉันไม่เข้าใจว่ามันหมายถึงอะไร
อยากทราบว่า copy-on-write คืออะไรและใช้ทำอะไร? คำว่า 'copy-on-write array' ถูกกล่าวถึงหลายครั้งในบทแนะนำ Sun JDK แต่ฉันไม่เข้าใจว่ามันหมายถึงอะไร
คำตอบ:
ฉันกำลังจะเขียนคำอธิบายของตัวเอง แต่บทความ Wikipedia นี้สรุปได้ค่อนข้างมาก
นี่คือแนวคิดพื้นฐาน:
Copy-on-write (บางครั้งเรียกว่า "COW") เป็นกลยุทธ์การเพิ่มประสิทธิภาพที่ใช้ในการเขียนโปรแกรมคอมพิวเตอร์ แนวคิดพื้นฐานคือหากผู้โทรหลายคนขอทรัพยากรซึ่งตอนแรกแยกไม่ออกคุณสามารถให้พวกเขาชี้ไปยังทรัพยากรเดียวกันได้ ฟังก์ชันนี้สามารถคงไว้ได้จนกว่าผู้โทรจะพยายามแก้ไข "สำเนา" ของทรัพยากรซึ่ง ณ จุดนั้นจะมีการสร้างสำเนาส่วนตัวที่แท้จริงเพื่อป้องกันไม่ให้ทุกคนเห็นการเปลี่ยนแปลง ทั้งหมดนี้เกิดขึ้นกับผู้โทรอย่างโปร่งใส ข้อได้เปรียบหลักคือหากผู้โทรไม่เคยทำการแก้ไขใด ๆ ก็ไม่จำเป็นต้องสร้างสำเนาส่วนตัว
นอกจากนี้นี่คือแอปพลิเคชั่นการใช้งานทั่วไปของ COW:
นอกจากนี้ยังใช้แนวคิด COW ในการบำรุงรักษาสแน็ปช็อตทันทีบนเซิร์ฟเวอร์ฐานข้อมูลเช่น Microsoft SQL Server 2005 สแน็ปช็อตแบบทันทีจะรักษามุมมองแบบคงที่ของฐานข้อมูลโดยการจัดเก็บสำเนาข้อมูลที่ปรับเปลี่ยนล่วงหน้าเมื่อมีการอัปเดตข้อมูลที่อยู่ด้านล่าง สแน็ปช็อตทันทีใช้สำหรับการทดสอบการใช้งานหรือรายงานที่ขึ้นอยู่กับช่วงเวลาและไม่ควรใช้เพื่อแทนที่การสำรองข้อมูล
clone()
เพื่อใช้fork()
- หน่วยความจำของกระบวนการพาเรนต์จะถูกควบคุมสำหรับเด็ก
"คัดลอกเมื่อเขียน" หมายถึงสิ่งที่ดูเหมือนมากหรือน้อย: ทุกคนมีสำเนาข้อมูลเดียวกันที่ใช้ร่วมกันเพียงสำเนาเดียวจนกว่าจะมีการเขียนข้อมูลจากนั้นจึงทำสำเนา โดยปกติการคัดลอกเมื่อเขียนจะใช้เพื่อแก้ไขปัญหาประเภทต่างๆที่เกิดขึ้นพร้อมกัน ตัวอย่างเช่นในZFSบล็อกข้อมูลบนดิสก์จะถูกจัดสรรแบบ copy-on-write ตราบเท่าที่ไม่มีการเปลี่ยนแปลงคุณยังคงบล็อกเดิมไว้ การเปลี่ยนแปลงเปลี่ยนเฉพาะบล็อกที่ได้รับผลกระทบ ซึ่งหมายความว่าจะมีการจัดสรรจำนวนบล็อกใหม่ขั้นต่ำ
การเปลี่ยนแปลงเหล่านี้มักจะถูกนำไปใช้เพื่อทำธุรกรรมกล่าวคือมีคุณสมบัติของกรด สิ่งนี้ช่วยขจัดปัญหาการเกิดพร้อมกันบางอย่างเพราะคุณรับประกันได้ว่าการอัปเดตทั้งหมดเป็นแบบปรมาณู
A
ตัวอย่างเช่นคุณมีบล็อกของข้อมูลที่เรียกว่า กระบวนการ1
, 2
, 3
, 4
แต่ละต้องการให้สำเนาของมันและเริ่มอ่านมันใน "Copy ในการเขียน" ระบบอะไรที่จะถูกคัดลอก ๆ A
ทุกอย่างจะยังคงอ่าน ตอนนี้กระบวนการ3
ต้องการที่จะทำให้เกิดการเปลี่ยนแปลงไปของสำเนาของA
กระบวนการ3
ในขณะนี้จะจริงทำสำเนาและสร้างบล็อกใหม่ของข้อมูลที่เรียกว่าA
B
กระบวนการ1
, 2
, 4
ยังคงอ่านบล็อกA
กระบวนการอยู่ในขณะนี้การอ่าน3
B
A
ควรสร้างสำเนาใหม่ หากคุณกำลังถามว่าจะเกิดอะไรขึ้นหากกระบวนการใหม่ทั้งหมดเกิดขึ้นและมีการเปลี่ยนแปลงA
คำอธิบายของฉันไม่ได้ให้รายละเอียดเพียงพอ นั่นจะเป็นการใช้งานที่เฉพาะเจาะจงและต้องการความรู้เกี่ยวกับวิธีที่คุณต้องการให้การใช้งานที่เหลือทำงานเช่นการล็อกไฟล์ \ ข้อมูลเป็นต้น
ฉันจะไม่ตอบซ้ำคำตอบเดียวกันใน Copy-on-Write ฉันคิดว่าคำตอบของแอนดรูว์และคำตอบของชาร์ลีนั้นชัดเจนมากแล้ว ฉันจะยกตัวอย่างจาก OS world เพื่อพูดถึงวิธีการใช้แนวคิดนี้อย่างกว้างขวาง
เราสามารถใช้fork()
หรือvfork()
เพื่อสร้างกระบวนการใหม่ vfork เป็นไปตามแนวคิดของการคัดลอกเมื่อเขียน ตัวอย่างเช่นกระบวนการลูกที่สร้างขึ้นโดย vfork จะแชร์ข้อมูลและส่วนของโค้ดกับกระบวนการหลัก ทำให้เวลาในการตีเร็วขึ้น คาดว่าจะใช้ vfork หากคุณแสดง exec ตามด้วย vfork ดังนั้น vfork จะสร้างกระบวนการย่อยซึ่งจะแชร์ข้อมูลและส่วนโค้ดกับพาเรนต์ แต่เมื่อเราเรียก exec มันจะโหลดอิมเมจของไฟล์ปฏิบัติการใหม่ในพื้นที่แอดเดรสของโปรเซสลูก
vfork
ไม่ใช้วัว ในความเป็นจริงหากเด็กเขียนอะไรบางอย่างอาจส่งผลให้เกิดพฤติกรรมที่ไม่กำหนดและไม่คัดลอกหน้า !! ในความเป็นจริงคุณสามารถพูดในทางกลับกันว่าเป็นความจริงบ้าง COW ทำหน้าที่เหมือนvfork
จนกว่าจะมีการแก้ไขบางอย่างในพื้นที่ที่ใช้ร่วมกัน!
เพื่อให้เป็นอีกตัวอย่างหนึ่งMercurial ใช้ copy-on-writeเพื่อทำการโคลนที่เก็บในเครื่องเป็นการดำเนินการที่ "ถูก" จริงๆ
หลักการก็เหมือนกับตัวอย่างอื่น ๆ ยกเว้นว่าคุณกำลังพูดถึงไฟล์ทางกายภาพแทนที่จะเป็นวัตถุในหน่วยความจำ ในขั้นต้นโคลนจะไม่ซ้ำกัน แต่เป็นฮาร์ดลิงก์ไปยังต้นฉบับ เมื่อคุณเปลี่ยนไฟล์ในโคลนสำเนาจะถูกเขียนขึ้นเพื่อแสดงเวอร์ชันใหม่
ฉันพบนี้บทความที่ดีเกี่ยวกับ zval ใน PHP ซึ่งกล่าวถึง COW เกินไป:
Copy On Write (ย่อว่า 'COW') เป็นเคล็ดลับที่ออกแบบมาเพื่อบันทึกหน่วยความจำ มีการใช้โดยทั่วไปในวิศวกรรมซอฟต์แวร์ หมายความว่า PHP จะคัดลอกหน่วยความจำ (หรือจัดสรรพื้นที่หน่วยความจำใหม่) เมื่อคุณเขียนลงในสัญลักษณ์หากอันนี้ชี้ไปที่ zval แล้ว
การคัดลอกเมื่อเขียนเป็นเทคนิคในการลดการใช้หน่วยความจำของสำเนาทรัพยากรโดยการแบ่งปันหน่วยความจำจนกว่าจะมีการแก้ไขสำเนาใดสำเนาหนึ่ง กล่าวอีกนัยหนึ่งสำเนาจะเป็นสำเนาเสมือนในตอนแรกและจะกลายเป็นสำเนาจริงในการดำเนินการเขียนครั้งแรกเท่านั้นจึงมีชื่อว่า 'copy-on-write'
ที่นี่หลังจากที่เป็นการนำงูหลามของเทคนิคการสำเนาเมื่อเขียนโดยใช้รูปแบบการออกแบบพร็อกซี่ ValueProxy
วัตถุ (คนพร็อกซี ) ใช้เทคนิคการคัดลอกเมื่อเขียนโดย:
Value
วัตถุที่ไม่เปลี่ยนรูป( เรื่อง );Value
วัตถุที่ไม่เปลี่ยนรูปใหม่ด้วยสถานะใหม่และการเชื่อมโยงแอตทริบิวต์หัวเรื่องกับValue
วัตถุที่ไม่เปลี่ยนรูปใหม่ValueProxy
อ็อบเจ็กต์ใหม่ที่ใช้แอ็ตทริบิวต์เรื่องเดียวกันกับValueProxy
อ็อบเจ็กต์ต้นฉบับimport abc
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 ValueProxy(BaseValue):
def __init__(self, subject):
self.subject = subject
def read(self):
return self.subject.read()
def write(self, data):
self.subject = Value(data)
def clone(self):
return ValueProxy(self.subject)
v1 = ValueProxy(Value('foo'))
v2 = v1.clone() # shares the immutable Value object between the copies
assert v1.subject is v2.subject
v2.write('bar') # creates a new immutable Value object with the new state
assert v1.subject is not v2.subject
นอกจากนี้ยังใช้ใน Ruby 'Enterprise Edition' เพื่อประหยัดหน่วยความจำ
ตัวอย่างที่ดีคือ Git ซึ่งใช้กลยุทธ์ในการจัดเก็บ Blobs ทำไมจึงใช้แฮช? ส่วนหนึ่งเป็นเพราะสิ่งเหล่านี้ง่ายต่อการดำเนินการที่แตกต่างกัน แต่ยังเป็นเพราะทำให้การเพิ่มประสิทธิภาพกลยุทธ์ COW ทำได้ง่ายขึ้น เมื่อคุณทำการคอมมิตใหม่โดยมีไฟล์เพียงไม่กี่ไฟล์การเปลี่ยนแปลงอ็อบเจ็กต์และต้นไม้ส่วนใหญ่จะไม่เปลี่ยนแปลง ดังนั้นการกระทำจะผ่านพอยน์เตอร์ต่างๆที่ทำจากแฮชจะอ้างอิงถึงกลุ่มของวัตถุที่มีอยู่แล้วทำให้พื้นที่จัดเก็บข้อมูลที่จำเป็นในการจัดเก็บประวัติทั้งหมดมีขนาดเล็กลงมาก
เป็นแนวคิดการป้องกันหน่วยความจำ ในคอมไพเลอร์นี้สร้างสำเนาพิเศษเพื่อแก้ไขข้อมูลในลูกและข้อมูลที่อัปเดตนี้จะไม่แสดงในข้อมูลผู้ปกครอง