Skip to content

Commit

Permalink
【新增】go sync.Map 原理
Browse files Browse the repository at this point in the history
  • Loading branch information
Yuu177 committed Dec 13, 2022
1 parent aed1593 commit 204ab75
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 1 deletion.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 60 additions & 0 deletions golang 高级编程/sync.Map实现.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Go sync.Map

go map 不是线程安全。我们可以通过加锁去实现并发安全,但是对整个 map 加锁粒度太大。所以 Go 1.9 引入了 `sync.Map`

## sync.Map 的结构

```go
// sync/map.go
type Map struct {
// 当写read map 或读写dirty map时 需要上锁
mu Mutex

// read map的 k v(entry) 是不变的,删除只是打标记,插入新key会加锁写到dirty中
// 因此对read map的读取无需加锁
read atomic.Value // 保存readOnly结构体

// dirty map 对dirty map的操作需要持有mu锁
dirty map[interface{}]*entry

// 当Load操作在read map中未找到,尝试从dirty中进行加载时(不管是否存在),misses+1
// 当misses达到diry map len时,dirty被提升为read 并且重新分配dirty
misses int
}

// read map数据结构
type readOnly struct {
m map[interface{}]*entry
// 为true时代表dirty map中含有m中没有的元素
amended bool
}

type entry struct {
// 指向实际的interface{}
// p有三种状态:
// p == nil: 键值已经被删除,此时,m.dirty==nil 或 m.dirty[k]指向该entry
// p == expunged: 键值已经被删除, 此时, m.dirty!=nil 且 m.dirty不存在该键值
// 其它情况代表实际interface{}地址 如果m.dirty!=nil 则 m.read[key] 和 m.dirty[key] 指向同一个entry
// 当删除key时,并不实际删除,先CAS entry.p为nil 等到每次dirty map创建时(dirty提升后的第一次新建Key),会将entry.p由nil CAS为expunged
p unsafe.Pointer // *interface{}
}
```

![sync.map 整体结构](.sync.Map实现.assets/20200505120255-16709237251825.png)

## sync.Map 实现的原理

1、过 read 和 dirty 两个字段将读写分离,读的数据存在只读字段 read 上,将最新写入的数据则存在 dirty 字段上。

2、读取时会先查询 read,不存在再查询 dirty,写入时则只写入 dirty。

3、读取 read 并不需要加锁,而读或写 dirty 都需要加锁。

4、另外有 misses 字段来统计 read 被穿透的次数(被穿透指需要读 dirty 的情况),超过一定次数则将 dirty 数据同步到 read 上。

5、对于删除数据则直接通过标记来延迟删除。

## 参考文章

- [深度解密 Go 语言之 sync.map](https://qcrao.com/post/dive-into-go-sync-map/)
- [Go sync.Map 实现](https://wudaijun.com/2018/02/go-sync-map-implement/)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 48 additions & 1 deletion 设计模式/工厂模式.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

## 简单工厂

![简单工厂](.工厂模式.assets/简单工厂.png)

- **工厂(Factory)**:根据客户提供的具体产品类的参数,创建具体产品实例。
- **抽象产品(AbstractProduct)**:具体产品类的基类,包含创建产品的公共方法。
- **具体产品(ConcreteProduct)**:抽象产品的派生类,包含具体产品特有的实现方法,是简单工厂模式的创建目标。
Expand Down Expand Up @@ -106,6 +108,51 @@ int main()

的确如此,但是这明显违背了开闭原则(对扩展开放,对修改关闭),即在扩展功能时修改了既有的代码。另一方面,简单工厂模式所有的判断逻辑都在工厂类中实现,一旦工厂类设计故障,则整个系统都受之影响。

## 工厂方法

简单工厂模式中,每新增一个具体产品,就需要修改工厂类内部的判断逻辑。为了不修改工厂类,遵循开闭原则,工厂方法模式中不再使用工厂类统一创建所有的具体产品,而是针对不同的产品设计了不同的工厂,每一个工厂只生产特定的产品。

![工厂方法](.工厂模式.assets/工厂方法.png)

从工厂方法模式简介中,可以该模式有以下几种角色

- **抽象工厂(AbstractFactory)**:所有生产具体产品的工厂类的基类,提供工厂类的公共方法。
- **具体工厂(ConcreteFactory)**:生产具体的产品工厂。
- **抽象产品(AbstractProduct)**:所有产品的基类,提供产品类的公共方法。
- **具体产品(ConcreteProduct)**:具体的产品类。

工厂方法模式 UML 类图如下:

待补充



代码如下:

待补充



如果要生产棒球(Baseball),只需要增加一个棒球工厂(Baseball Facory),然后在客户端代码中修改具体工厂类的类名,而原有的类的代码无需修改。由此可看到,相较简单工厂模式,工厂方法模式更加符合开闭原则。工厂方法是使用频率最高的设计模式之一,是很多开源框架和 API 类库的核心模式。

工厂方法优点:

- 工厂方法用于创建客户所需产品,同时向客户隐藏某个具体产品类将被实例化的细节,用户只需关心所需产品对应的工厂。
- 工厂自主决定创建何种产品,并且创建过程封装在具体工厂对象内部,多态性设计是工厂方法模式的关键。
- 新加入产品时,无需修改原有代码,增强了系统的可扩展性,符合开闭原则。

工厂方法缺点:

- 添加新产品时需要同时添加新的产品工厂,系统中类的数量成对增加,增加了系统的复杂度,更多的类需要编译和运行,增加了系统的额外开销;
- 工厂和产品都引入了抽象层,客户端代码中均使用的抽象层(AbstractFactory 和 AbstractSportProduct ),增加了系统的抽象层次和理解难度。

## 抽象工厂

![avatar](.工厂模式.assets/抽象工厂模式UML实例图.png)

## 参考链接

- [简单工厂模式简介](https://github.com/FengJungle/DesignPattern/blob/master/01.SimpleFactory/01.SimpleFactory.md)
- [简单工厂模式简介](https://github.com/FengJungle/DesignPattern/blob/master/01.SimpleFactory/01.SimpleFactory.md)
- [工厂方法模式简介](https://github.com/FengJungle/DesignPattern/blob/master/02.FactoryMethod/02.FactoryMethod.md)

- [抽象工厂模式简介](https://github.com/FengJungle/DesignPattern/blob/master/03.AbstractFactory/03.AbstractFactory.md)

0 comments on commit 204ab75

Please sign in to comment.