如果这种方式导致程序明显变慢或者引起其他问题,我们要重新思考来通过 goroutines 和 channels 来解决问题
https://github.com/Unknwon/the-way-to-go_ZH_CN/blob/master/eBook/09.3.md
9.3 锁和 sync 包
在一些复杂的程序中,通常通过不同线程执行不同应用来实现程序的并发。当不同线程要使用同一个变量时,经常会出现一个问题:无法预知变量被不同线程修改的顺序!(这通常被称为资源竞争,指不同线程对同一变量使用的竞争)显然这无法让人容忍,那我们该如何解决这个问题呢?
经典的做法是一次只能让一个线程对共享变量进行操作。当变量被一个线程改变时(临界区),我们为它上锁,直到这个线程执行完成并解锁后,其他线程才能访问它。
特别是我们之前章节学习的 map 类型是不存在锁的机制来实现这种效果(出于对性能的考虑),所以 map 类型是非线程安全的。当并行访问一个共享的 map 类型的数据,map 数据将会出错。
在 Go 语言中这种锁的机制是通过 sync 包中 Mutex 来实现的。sync 来源于 "synchronized" 一词,这意味着线程将有序的对同一变量进行访问。
sync.Mutex 是一个互斥锁,它的作用是守护在临界区入口来确保同一时间只能有一个线程进入临界区。
假设 info 是一个需要上锁的放在共享内存中的变量。通过包含 Mutex 来实现的一个典型例子如下:
import "sync"
type Info struct {
mu sync.Mutex
// ... other fields, e.g.: Str string
}
如果一个函数想要改变这个变量可以这样写:
func Update(info *Info) {
info.mu.Lock()
// critical section:
info.Str = // new value
// end critical section
info.mu.Unlock()
}
还有一个很有用的例子是通过 Mutex 来实现一个可以上锁的共享缓冲器:
type SyncedBuffer struct {
lock sync.Mutex
buffer bytes.Buffer
}
在 sync 包中还有一个 RWMutex 锁:他能通过 RLock() 来允许同一时间多个线程对变量进行读操作,但是只能一个线程进行写操作。如果使用 Lock() 将和普通的 Mutex 作用相同。包中还有一个方便的 Once 类型变量的方法 once.Do(call),这个方法确保被调用函数只能被调用一次。
相对简单的情况下,通过使用 sync 包可以解决同一时间只能一个线程访问变量或 map 类型数据的问题。如果这种方式导致程序明显变慢或者引起其他问题,我们要重新思考来通过 goroutines 和 channels 来解决问题,这是在 Go 语言中所提倡用来实现并发的技术。我们将在第 14 章对其深入了解,并在第 14.7 节中对这两种方式进行比较。
如果这种方式导致程序明显变慢或者引起其他问题,我们要重新思考来通过 goroutines 和 channels 来解决问题的更多相关文章
- Response.Write()方法响应导致页面字体变大的解决办法
关于ASP.NET中用Response.Write()方法响应导致页面字体变大的解决办法 最近研究了ASP.NET,发现一个问题,比方说在页面里面有个Button,要点击以后要打开新窗口,而且 ...
- 无辜的RAD(RAD是让你去创造和使用可复用的组件,不是让程序员“变白痴”)good
无辜的RAD 2005-3-21 说实话,RAD很无辜.从出生的那天其就被骂,天天被指着鼻子说“不就是拖个控件嘛”,就好像当年说学电脑“不就是插个鼠标嘛”.也怪程序员大都天性犯贱,就爱一遍又一便的写基 ...
- 头疼3-4次的问题,数据从DB导出到EXCEL,再从EXCEL导入到DB,数据格式发生错误 ,导致 程序出错。
反思: 1 解决 问题的思路 绕远了: 在这个问题出现前,程序是运行正确 的 问题出现前,我误删了DB 的 testcase表的所有 case ,然后 再把邮件 中的excel数据导入到 DB 然后 ...
- WPF 线程中异常导致程序崩溃
一般我们WPF中都加全局捕获,避免出现异常导致崩溃. Application.Current.DispatcherUnhandledException += Current_DispatcherUnh ...
- thinkphp关闭调试模式(APP_DEBUG => false),导致程序出错
thinkphp关闭调试模式(APP_DEBUG => false),导致程序出错,开启调试模式,不报错,怎么解决? 查看Logs日志记录: [ --29T09::+: ] 113.108.11 ...
- Android Studio 创建不恰当的虚拟设备导致程序不正常运行
操作系统:Windows 10 x64 IDE:Android Studio 3.2.1 使用Android Studio新建第一个Android程序,一开始在虚拟设备上面调试,不管程序怎么修改,运行 ...
- linux 使用不安全的sprintf函数,存储字符越界导致程序莫名崩溃问题
linux c++编程 问题背景: 在处理一个公共模块的代码中,其中有以下代码片段 //代码片段-组合一组字符串并存放到szSignKey数组中 ] = {}; sprintf(szSignKey, ...
- 【PyCharm疑问】在pycharm中带有中文时,有时会导致程序判断错误,是何原因?
1.会导致程序打印false错误的代码如下: # -*- coding:utf-8 -*- import os import sys from uiautomator import device as ...
- 内核futex的BUG导致程序hang死问题排查
https://mp.weixin.qq.com/s/sGS-Kw18sDnGEMfQrbPbVw 内核futex的BUG导致程序hang死问题排查 原创: 王领先 58架构师 今天 近日,Had ...
随机推荐
- Educational Codeforces Round 35 B. Two Cakes【枚举/给盘子个数,两份蛋糕块数,最少需要在每个盘子放几块蛋糕保证所有蛋糕块都装下】
B. Two Cakes time limit per test 1 second memory limit per test 256 megabytes input standard input o ...
- 在typescript中import第三方类库clipboard报错
一.问题 在实际开发项目中就遇到了这样的问题,需要在Vue+Typescript项目中添加复制文本的功能,就找了clipboard插件,先是新建了一个新的项目用来实验看看是否好用,都写好了以后发给别人 ...
- 笔记-迎难而上之Java基础进阶7
序列化流 把对象以流的方式写入到文件中保存,叫做对象的序列化 把文件中保存的对象,以流的方式读取出来,叫做对象大反序列化 对象的序列化流_ObjectOutputtream继承自OutputStrea ...
- 转:Maven项目中获取classpath和资源文件的路径
假设资源文件放在maven工程的 src/main/resources 资源文件夹下,源码文件放在 src/main/java/下, 那么java文件夹和resources文件夹在运行时就是class ...
- WinForm版聊天室复习Socket通信
聊天室:服务器端-------------客户端 最终演示展示图: 一. 服务器端 对服务端为了让主窗体后台不处理具体业务逻辑,因此对服务端进行了封装,专门用来处理某个客户端通信的过程. 而由于通信管 ...
- 【IntelliJ IDEA】升级之后又要激活的解决方法
用了几个月的idea,在它升级之后,又不听话了.启动时候需要重新激活. 解决方法: 1.找到C:\Windows\System32\drivers\etc\下的hosts文件 在文件中添加如下: 0. ...
- 从需求的角度去理解Linux系列:总线、设备和驱动
笔者成为博客专家后整理以前原创的嵌入式Linux系列博文,现推出以让更多的读者受益. <从需求的角度去理解linux系列:总线.设备和驱动>是一篇有关如何学习嵌入式Linux系统的方法论文 ...
- 如何删除mysql 主键索引
如果一个主键是自增长的,不能直接删除该列的主键索引, 应当先取消自增长,再删除主键特性 alter table 表名 drop primary key; [如果这个主键是自增的,先取消自增长.] ...
- apache hadoop 2.4.0 64bit 在windows8.1下直接安装指南(无需虚拟机和cygwin)
工作须要.要開始搞hadoop了,又是大数据,自己感觉大数据.云.仅仅是ERP.SOAP风潮之后与智能地球一起诞生的概念炒作. 只是Apache是个奇妙的组织.Java假设没有它也不会如今如火中天.言 ...
- 重读金典------高质量C编程指南(林锐)-------第七章 内存管理
2015/12/10补充: 当我们需要给一个数组返回所赋的值的时候,我们需要传入指针的指针.当我们只需要一个值的时候,传入指针即可,或者引用也可以. 结构大致如下: char* p = (char*) ...