15.手撕Go语言-并发编程

并发编程开发将一个过程按照并行算法拆分为多个可以独立执行的代码块,从而充分利用多核和多处理器提高系统吞吐率

顺序、并发与并行

  1. 顺序是指发起执行的程序只能有一个

  2. 并发是指同时发起执行(同时处理)的程序可以有多个(单车道并排只能有一辆车,可同时驶入路段多辆车)

  3. 并行是指同时执行(同时做)的程序可以有多个 (多车道并排可以有多个车)

例程(Goroutine)

Go语言中每个并发执行的单元叫Goroutine,使用go关键字后接函数调用来创建一个Goroutine

15.01.png

main函数也是由一个例程来启动执行,这个例程称为主例程,其他例程叫工作例程。主例程结束后工作例程也会随之销毁,使用sync.WaitGroup(计数信号量)来维护执行例程执行状态

15.02.png

可以通过runtime包中的GoSched让例程主动让出CPU,也可以通过time.Sleep让例程休眠从而让出CPU

闭包陷阱

15.03.png

因为闭包使用函数外变量,当例程执行是,外部变量已经发生变化,导致打印内容不正确,可使用在创建例程时通过函数传递参数(值拷贝)方式避免

并发程序通信方式

共享数据(同步)

多个并发程序需要对同一个资源进行访问,则需要先申请资源的访问权限,同时再使用完成后释放资源的访问权。当资源被其他程序已申请访问权后,程序应该等待访问权被释放并被申请到时进行访问操作。同一时间资源只能被一个程序访问和操作

管道(异步)

数据处理者处理完数据后将数据放入缓冲区中,数据接收者从缓冲区中获取数据,处理者不用等待接收者是否准备好处理数据

共享数据

15.04.png

多个例程对同一个内存资源进行修改,未对资源进行同步限制,导致修改数据混乱

互斥锁

Go语言中sync包中提供了Mutex(互斥锁),可以用于对资源加锁和释放锁提供对资源同步方式访问

15.05.png

原子操作

原子操作是指过程不能中断的操作s,go语言sync/atomic包中提供提供了五类原子操作函数,其操作对象为整数型或整数指针

  1. Add*:增加/减少
  2. Load*:载入
  3. Store*:存储
  4. Swap*:更新
  5. CompareAndSwap*:比较第一个参数引用指是否与第二个参数值相同,若相同则将第一个参数值更新为第三个参数
15.06.png

管道

在go语言中可以通过chan来定义管道,可以通过操作符<-和->对管道进行读取和写入操作

通过管道维护例程状态

15.07.png

声明

管道是声明需要指定管道存放数据的类型,管道原则可以存放任何类型,但只建议用于存放值类型或者只包含值类型的结构体。在管道声明后,会被初始化为nil

15.08.png

初始化

使用make函数初始化,make(chan type)/make(chan type, len),不带len参数的用于创建无缓存区的管道,使用len创建指定缓冲区长度的管道

15.09.png

读取和写入

可通过操作符<-和->对管道进行读取和写入操作,当写入无缓冲区管道或由缓冲区管道已满时写入则会阻塞直到管道中元素被其他例程读取。同理,当管道中无元素时读取时也会阻塞到管道被其他例程写入元素

15.10.png

关闭管道

可通过close函数关闭管道,关闭后的管道不能被写入,当读取到最后一个元素后可通过读取的第二个参数用于判断是否结束

15.11.png

for-range遍历管道

管道也可以通过for-range进行遍历

15.12.png

只读和只写管道

可以在函数参数时声明管道为chan<-或chan->,表示管道只写或只读

15.13.png

select-case语句

当写入无缓冲区管道或由缓冲区管道已满时写入则会阻塞直到管道中元素被其他例程读取。同理,当管道中无元素时读取时也会阻塞到管道被其他例程写入元素,若需要同时对多个管道进行监听(写入或读取),则可以使用select-case语句

15.14.png

select语句自上到下执行case语句中对管道的读取和写入,当操作成功则执行对应子语句,否则执行下一个case语句,当所有case都失败,则执行default语句,default语句可省略

超时机制

可以通过select-case实现对执行操作超时的控制

15.15.png

Select-case语句监听每个case语句中管道的读取,当某个case语句中管道读取成功则执行对应子语句

Go语言time包实现了After函数,可以用于实现超时机制,After函数返回一个只读管道

15.16.png

sync包

sync包提供了同步原语,常用结构体有:

  • sync.Mutex:互斥锁

  • sync.RWMutex:读写锁

  • sync.Cond:条件等待

  • sync.Once:单次执行

    15.17.png
  • sync.Map:例程安全映射

  • sync.Pool:对象池

  • sync.WaitGroup:组等待

runtime包

runtime包提供了与Go运行时系统交互的操作,常用函数:

  • runtime.Gosched(): 当前goroutine让出时间片
  • runtime.GOROOT(): 获取Go安装路径
  • runtime.NumCPU(): 获取可使用的逻辑CPU数量
  • runtime.GOMAXPROCS(1):设置当前进程可使用的逻辑CPU数量
  • runtime.NumGoroutine(): 获取当前进程中goroutine的数量
15.18.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351