写时复制
写时复制(Copy-on-Write, CoW)最核心思路:只有当数据被修改时,才真正复制一份新的数据副本。在修改之前,所有使用者共享同一份数据。
假设我们有一个共享数据对象 data = "A"
初始状态:
有两个变量
a
和b
都指向这个数据
a → ["A"] ↑ b ─────┘
当
a
要修改数据(比如改成"B"):系统发现
a
和b
共享同一份数据先复制:创建数据的新副本 "B"
再修改:让
a
指向新副本原数据保留:
b
仍然指向旧数据 "A"
a → ["B"] (新副本)
b → ["A"] (原数据)
核心原则:
读操作:不复制,多个读者共享同一份数据
写操作:先复制再修改,确保修改不会影响其他使用者
package main
import "fmt"
type database struct {
data int // 原始数据
}
type snapshot struct {
data *int // 指向原始数据指针
}
var sna = &snapshot{}
func (d *database) createShot() *snapshot {
return &snapshot{data: &d.data} // 创建快照,只共享指针
}
func (d *database) clone() *snapshot {
s := d.data
return &snapshot{data: &s} // 复制新快照
}
func (d *database) set() {
sna = d.clone() // 触发写时复制,复制一份给快照
d.data = 1 // 修改原数据
}
func main() {
d := database{data: 2}
sna = d.createShot()
fmt.Println(*sna.data) // 2
d.set() // 写时复制:源数据修改,快照复制数据
fmt.Println(d.data) // 1
fmt.Println(*sna.data) // 2
}
写时复制的三个黄金法则:
读共享:多个读者共享同一份数据
写分离:写操作时自动创建新副本
零复制:没有修改时不做任何数据拷贝
共享指针直到修改时刻,修改前才真正复制数据
最后更新于