您好!欢迎来到爱源码

爱源码

热门搜索: 抖音快手短视频下载   

去方言记忆模型和发生之前 《互站网》

  • 时间:2022-06-29 00:39 编辑: 来源: 阅读:293
  • 扫一扫,手机访问
摘要:去方言记忆模型和发生之前 《互站网》
来自public # public #: Gopher参考North Go内存模型,明确指出一个goroutine如何观察其他Go routine对同一个变量的写操作。 当多个goroutine并发访问同一数据时,有必要对并发访问操作进行序列化。 Go中读写的序列化可以通过通道通信或者其他同步原语(比如sync包中的互斥锁、sync/atomic中的读写锁和原子操作)来保证 发生在单个goroutine之前,读写的行为必须与程序指定的执行顺序一致。 换句话说,编译器和解算器可以在单个goroutine中重新排序指令,而不改变语言规范定义的行为。 A := 1b := 2由于指令重排序,b := 2可能在a := 1之前执行。 在单个goroutine中,执行顺序的调整不会影响最终结果。 但是,在多个goroutine场景中可能会出现问题。 Var,b int//goro utine ago func(){ a:= 5b:= 1 }()//goro utine Bgoffunc(){ for b = = 1 { } fmt。println (a)}()执行上述代码时,预计goroutine b可以正常输出5,但由于指令重排,b 注意:上面的例子是不正确的,仅供说明。 为了明确读写操作的要求,Go中引入了happens before,表示执行内存操作的一种偏序关系。 发生前的作用当多个例程访问一个共享变量时,它们必须建立同步事件来保证发生前的条件,从而保证读操作可以观察到预期的写操作。 如果事件e1发生在事件e2之前,那么我们说e2发生在e1之后。 同样,如果e1不发生在e2之前或之后,那么我们说e1和e2同时发生。 在单个goroutine中,发生之前的顺序就是程序执行的顺序。 之前发生的顺序是什么?我们来看以下几个条件。 如果变量V的读操作R和写操作W满足以下两个条件,R将允许观察到W: R不发生在W之前。 在W之后和r之前没有其他写操作发生。 为了确保变量V的读操作R可以观察到特定的写操作W,需要确保W是唯一允许被R观察到的写操作。 那么,如果R和W都满足以下条件,R可以保证W: W发生在R之前。 其余的写操作发生在W之前和r之后。 单个goroutine没有并发,这两个条件是等价的。 徐在此基础上进行了扩展,这两组条件等价于单核运行环境。 在并发的情况下,后一组条件比第一组条件更严格。 如果你很迷茫,那就对了!许一开始也很疑惑。这两组条件是一样的。 为此,老徐作了反复的比较与参考,以确保上述理解是没有问题的。 图片:我们换个思路,进行逆向推理。 如果这两组条件相同,就不需要写两次引用。果然不简单。 在继续分析image之前,我要感谢我的语文老师。没有你,我找不到他们的区别。 如果R不发生在W之前,R可能的情况是R发生在W之后或者R和W同时发生,如下图所示(实线表示R可以同时发生) 如果在W之后和R之前没有发生其他的映像写操作,则剩余的写操作W '可能发生在W之前或者与W同时,或者在R之后或者与R同时,如下图所示(实线表示同时) 图像第二组条件非常明确,w发生在r之前,其余的写操作只能发生在w之前或r之后,如下图所示(空表示它们不能同时发生) Image这里应该明白为什么第二套条件比第一套条件严格了。 第一组允许观察W,第二组保证观察W。 Go中的同步下面是Go中几个约定好的同步事件,可以保证程序遵循happens-before规则,从而使并发的goroutine相对有序。 Go的初始化程序被初始化为在单个goroutine中运行,但是这个goroutine可以创建并发运行的其他go routine。 如果包P被导入到包Q中,包Q的init函数的执行在包P的init函数执行之前结束。 main函数的执行发生在所有init函数执行之后。 goroutine的建立结束了。goroutine是在goroutine被处决之前成立的。 徐一直认为这基本上是胡说八道,但事情总是没有这么简单。言下之意是goroutine的创建受阻。 fun sleep()bool { time . sleep(time . second)return true } gofmt . println(sleep())上面的代码会阻塞主goroutine一秒钟,然后创建一个子goroutine。 goroutine的退出是不可预测的。 如果使用一个goroutine来观察另一个goroutine,请使用lock或Channel来确保相对顺序。 发送通道和接收通道的通信是goroutine之间同步的主要方式。 通道的发送动作先于相应的接收动作的完成。 无缓冲通道的接受先于该通道上传输的完成。 总结起来,这两点就是四个动作:开始发送、开始接收、完成发送、完成接收,它们的时序关系如下 发送>:完成接收开始接收>:发送完成注意:发送和接收之间没有明确的顺序。通道关闭发生在由于通道关闭而返回零接受之前。 容量为C的信道的第k次接受先于该信道上第k+C次传输的完成。 这里用极限法应该更容易理解。如果C为0,K为1,其含义与无缓冲通道相同。 锁定任何同步。互斥或同步。RWMutex变量l和n 假设n为1,m为2,在第二次调用l.Lock()返回之前,必须调用l.UnLock()。 sync的变量l有这样一个n。RWMutex表示l.RLock()的调用返回发生在第n个l.Unlock()之后,而匹配的l.RUnlock()发生在第n个l.Lock()之前。 不得不说,上面这句话简直让人无法理解。 徐总翻译成人:有写锁的时候:l.RLock()的调用返回发生在l.Unlock()之后。 带读锁:对l.RUnlock()的调用发生在l.Lock()之前 注意:在调用l.RUnlock()之前不调用l.RLock(),在调用l.Unlock()之前不调用l.Lock(),都会导致死机。 一次f的回归。在任何其他once.do的返回之前。 不正确同步错误的例子-var a,b int func f(){ a = 1b = 2 } func g(){ print(b)print(a)} func main(){ go f()g()}这个例子看起来相当简单,但是老徐认为大多数人应该忽略指令重排序导致的异常输出。 如果在goroutine f指令重新排序后,b=2发生在a=1之前,那么主goroutine观察到B的变化,而不是A的变化,因此有可能输出20。 徐在当地尝试过多次,结果都是输出00,20。这种产出预计只能在理论上实现。 错误2 var a string var done bool func setup(){ a = " hello,world " done = true } func do print(){ if!done { once . do(setup)} print(a)} functowprint(){ go do print()go do print()}这种双重检测旨在避免同步的开销,但仍然可以打印出一个空字符串,而不是“hello,world” 说实话,老徐自己也不能保证他以前没有写过这样的代码。 现在,唯一可以想象的场景是,当其中一个goroutine do打印执行到done=true(指令重新排序导致done = true在a="hello,world "之前执行)时,另一个goroutine do通过观察done的值为true来打印一个空字符串。 最后,衷心希望本文对读者有所帮助。 当然,如果你发现任何错误,请联系老徐纠正它们。 参考https://golang.org/ref/mem


  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【技术支持|常见问题】1502企业站群-多域名跳转-多模板切换(2024-04-09 12:19)
【技术支持|常见问题】1126完美滑屏版视频只能显示10个(2024-03-29 13:37)
【技术支持|常见问题】响应式自适应代码(2024-03-24 14:23)
【技术支持|常见问题】1126完美滑屏版百度未授权使用地图api怎么办(2024-03-15 07:21)
【技术支持|常见问题】如何集成阿里通信短信接口(2024-02-19 21:48)
【技术支持|常见问题】算命网微信支付宝产品名称年份在哪修改?风水姻缘合婚配对_公司起名占卜八字算命算财运查吉凶源码(2024-01-07 12:27)
【域名/主机/服务器|】帝国CMS安装(2023-08-20 11:31)
【技术支持|常见问题】通过HTTPs测试Mozilla DNS {免费源码}(2022-11-04 10:37)
【技术支持|常见问题】别告诉我你没看过邰方这两则有思想的创意广告! (2022-11-04 10:37)
【技术支持|常见问题】你正确使用https了吗? [php源码](2022-11-04 10:37)

联系我们
Q Q:375457086
Q Q:526665408
电话:0755-84666665
微信:15999668636
联系客服
企业客服1 企业客服2 联系客服
86-755-84666665
手机版
手机版
扫一扫进手机版
返回顶部