当前位置: 首页 > news >正文

招工网站58同城专业网络推广公司排名

招工网站58同城,专业网络推广公司排名,定西企业网站制作,小程序推广方式有哪些在学习 Go 编程语言时,您可能会遇到这句著名的格言:“不要通过共享内存来进行通信;相反,通过通信来共享内存。” 这句话构成了 Go 强大并发模型的基础,其中通道(channels)作为协程之间的主要通信…

在学习 Go 编程语言时,您可能会遇到这句著名的格言:“不要通过共享内存来进行通信;相反,通过通信来共享内存。” 这句话构成了 Go 强大并发模型的基础,其中通道(channels)作为协程之间的主要通信工具。然而,虽然通道是管理并发的多功能工具,但错误地假设我们应该始终用通道替换传统的锁定机制,如 Mutex,是一个错误的观念。在某些情况下,使用 Mutex 不仅恰当,而且比通道更有效。

在我的 Go 并发可视化系列中,今天我将通过视觉方式来解释 sync.Mutex

Golang 基础

场景

想象一下,有四位 Gopher 自行车手每天骑车上班。他们都需要在到达办公室后洗个澡,但办公室只有一个浴室。为了防止混乱,他们确保一次只能有一个人使用浴室。这种独占式访问的概念正是 Go Mutex(互斥锁)的核心。

bf34c38a3f6fc9ab2d159ffe05b90bbd.png

每天早上在办公室洗澡对自行车手和跑步者来说是一个小小的竞争。

普通模式

今天最早到达的是 Stringer。当他来的时候,没有人在使用浴室,因此他可以立即使用浴室。

对一个未加锁的 Mutex 调用 Lock() 会立即成功。

片刻后,Partier 到了。Partier 发现有人在使用浴室,但他不知道是谁,也不知道什么时候会结束使用。此时,他有两个选择:站在浴室前面(主动等待),或者离开并稍后再回来(被动等待)。按 Go 的术语,前者被称为“自旋”(spinning)。自旋的协程会占用 CPU 资源,增加了在锁定可用时获取 Mutex 的机会,而无需进行昂贵的上下文切换。然而,如果 Mutex 不太可能很快可用,继续占用 CPU 资源会降低其他协程获取 CPU 时间的机会。

从版本 1.21 开始,Golang 允许到达的协程自旋一段时间。如果在指定时间内无法获取 Mutex,它将进入休眠状态,以便其他协程有机会运行。

14dea1bc70160aedd59d555282387957.png

到达的协程首先自旋,然后休眠。

Candier 到了。就像 Partier 一样,她试图获取浴室。

1713dbf0667141489a7a37329b5932b3.png

因为她刚到,如果 Stringer 很快释放浴室,她就有很大的机会在被动等待之前获取它。这被称为普通模式。

普通模式的性能要好得多,因为协程可以连续多次获取 Mutex,即使有阻塞的等待者。

802c169f355683c6be50192d2c2b88c1.png
1*GJ7OW0_8z_8QjXPa2cFxPw.png

go/src/sync/mutex.go at go1.21.0 · golang/go · GitHub[1]

新到达的协程在争夺所有权时具有优势

饥饿模式

Partier 回来了。由于他等待的时间很长(超过 1 毫秒),他将尝试以饥饿模式获取浴室。当 Swimmer 来时,他注意到有人饿了,他不会尝试获取浴室,也不会自旋。相反,他会排队在等待队列的尾部。

在这种饥饿模式下,当 Candier 结束时,她会直接把浴室交给 Partier。此时没有竞争。

b37df75b60e60bc216fc9153faa06bc4.png

饥饿模式是防止尾延迟的病理情况的重要措施。

1411210b8c3edaa0fa92edf479dbc3a9.png
7d4dfe9465324ba15876a95a37811c01.png

Partier 完成了他的回合并释放了浴室。此时,只有 Swimmer 在等待,因此他将立即拥有它。Swimmer 如果发现自己是最后一个等待的人,他会将 Mutex 设置回普通模式。如果他发现自己的等待时间少于 1 毫秒,也会这样做。

最后,Swimmer 在使用浴室后释放了它。请注意,Mutex 不会将所有者从“已锁定(由 Goroutine A 锁定)”状态更改为“已锁定(由 Goroutine B 锁定)”状态。它始终会在“已锁定”到“未锁定”然后再到“已锁定”的状态之间切换。出于简洁起见,上面的图像中省略了中间状态。

展示代码!

Mutex 的实现随时间而变化,实际上,要完全理解它的实现并不容易。幸运的是,我们不必完全理解其实现就能高效使用它。如果从这篇博客中只能记住一件事,那一定是:早到的人不一定赢得比赛。相反,新到达的协程通常具有更高的机会,因为它们仍在 CPU 上运行。Golang 还尝试避免通过实现饥饿模式来使等待者被饿死。

package mainimport ("fmt""sync""time"
)func main() {wg := sync.WaitGroup{}wg.Add(4)bathroom := sync.Mutex{}takeAShower := func(name string) {defer wg.Done()fmt.Printf("%s: I want to take a shower. I'm trying to acquire the bathroom\n", name)bathroom.Lock()fmt.Printf("%s: I have the bathroom now, taking a shower\n", name)time.Sleep(500 * time.Microsecond)fmt.Printf("%s: I'm done, I'm unlocking the bathroom\n", name)bathroom.Unlock()}go takeAShower("Partier")go takeAShower("Candier")go takeAShower("Stringer")go takeAShower("Swimmer")wg.Wait()fmt.Println("main: Everyone is Done. Shutting down...")
}

正如您可能猜到的,并发代码的结果几乎总是非确定性的。

第一次

Swimmer: I want to take a shower. I'm trying to acquire the bathroom

Partier: I want to take a shower. I'm trying to acquire the bathroom

Candier: I want to take a shower. I'm trying to acquire the bathroom

Stringer: I want to take a shower. I'm trying to acquire the bathroom

Swimmer: I have the bathroom now, taking a shower

Swimmer: I'm done, I'm unlocking the bathroom

Partier: I have the bathroom now, taking a shower

Partier: I'm done, I'm unlocking the bathroom

Candier: I have the bathroom now, taking a shower

Candier: I'm done, I'm unlocking the bathroom

Stringer: I have the bathroom now, taking a shower

Stringer: I'm done, I'm unlocking the bathroom

main: Everyone is Done. Shutting down...

第二次

Swimmer: I want to take a shower. I'm trying to acquire the bathroom

Swimmer: I have the bathroom now, taking a shower

Partier: I want to take a shower. I'm trying to acquire the bathroom

Stringer: I want to take a shower. I'm trying to acquire the bathroom

Candier: I want to take a shower. I'm trying to acquire the bathroom

Swimmer: I'm done, I'm unlocking the bathroom

Partier: I have the bathroom now, taking a shower

Partier: I'm done, I'm unlocking the bathroom

Stringer: I have the bathroom now, taking a shower

Stringer: I'm done, I'm unlocking the bathroom

Candier: I have the bathroom now, taking a shower

Candier: I'm done, I'm unlocking the bathroom

main: Everyone is Done. Shutting down...

自己实现 Mutex

实现 sync.Mutex 是困难的,但使用具有缓冲的通道来实现 Mutex 却相当容易。

type MyMutex struct {ch chan bool
}func NewMyMutex() *MyMutex {return &MyMutex{// 缓冲大小必须为 1ch: make(chan bool, 1),}
}// Lock 锁定 m。
// 如果锁已被使用,调用的协程将被阻塞,直到 Mutex 可用。
func (m *MyMutex) Lock() {[m.ch](http://m.ch) <- true
}// Unlock 解锁 m。
func (m *MyMutex) Unlock() {<-m.ch
}

这篇文章通过生动的场景和可视化效果很好地解释了 Go 语言中 sync.Mutex 的工作原理,以及如何使用互斥锁来管理并发

相关系列文章

使用通信顺序进程(CSP)模型的 Go 语言通道

Go并发可视化解释 – select语句

以可视化方式解释 Go 并发 - 通道

http://www.hkea.cn/news/195885/

相关文章:

  • 网站如何做导航条下拉菜单怎么做百度网页
  • 网站开发都做什么平台推广精准客源
  • 网站建设共享ip宁波seo搜索引擎优化
  • 学校网站建设必要性搜索引擎排名
  • 哪里有做区块链网站的百度网址大全在哪里找
  • 加盟平台网站怎么做竞价托管多少钱一个月
  • wordpress 微信 代码网站关键词怎么优化排名
  • 网站推广维护考研培训班哪个机构比较好
  • 网站后台生成器人工智能培训班收费标准
  • 在线做app的网站武汉网络营销公司排名
  • 了解深圳网站页面设计潍坊百度关键词优化
  • 制作网站怎样找公司来帮做seo词条
  • 网络销售有哪些站长工具seo排名
  • 做房产中介网站怎么注册一个自己的网站
  • 天津网站设计成功柚米全网推广成功再收费
  • 建设公司网站靠谱吗企业网站设计制作
  • 电子商务学什么课程内容兰州搜索引擎优化
  • 沧州网站建设制作设计优化能打开的a站
  • 石家庄网站建设推广报价怎么让百度快速收录网站
  • 建设局网站上开工日期选不了制作网站需要多少费用
  • 犬舍网站怎么做网页推广怎么做
  • 镇江核酸检测最新通知如何优化网页加载速度
  • wpf入可以做网站吗竞价托管外包费用
  • 公司设计网站需要包含什么资料优化排名软件
  • 日本樱花云服务器wan亚马逊seo关键词优化软件
  • layui框架的wordpress厦门站长优化工具
  • 微网站设计尺寸培训课程总结
  • 保险平台官网湖北搜索引擎优化
  • 西安微信小程序制作公司关键词优化方法
  • 手机网站建设用乐云seo搜索引擎是什么意思啊