13 Go并发编程初探

一、Go并发编程概述

Go以并发性能强大著称,在在语言级别就原生支持,号称能实现百万级并发,并以此独步江湖,本专题我们开始学习Go并发编程。

为深入了解到Go并发的各种特性,该专题会分四部分展开:

简单来说,Go的并发编程由协程(goroutine)和管道(channel)两个设计机制实现,其中协程可以理解为微线程,管道也叫通道。这两个核心机制实现了go并发的基本运行单元和通信机制。而为go高并发性能提供支持的,是go运行时内部的协程调度器,其基于MPG调度模型。当然,Go并发编程也是有陷阱的,稍有不慎就会造成死锁退出,这方面我们需要着重避免。另外并发也有一定的安全问题,对资源无控制的访问肯定会造成数据混乱,Go提供sync包实现同步机制,让一些不适合并发的场景有同步的支持。最后介绍几种Go并发编程的范式,让你在实战中能够巧妙的构建程序。

二、并发编程初探

并发是由来已久的概念,多个任务同时执行能够为程序得到指数级增长的效率,在讲Go的并发编程前我们需要理清几个概念,以让我们更了解Go并发的实现。

1.异步与同步
  • 同步 sync:同步就是顺序执行,执行完一个再执行下一个,需要等待、协调运行;
  • 异步 async:与同步相对,异步就是彼此独立,在等待某事件的过程中继续做自己的事,不需要等待这一事件完成后再工作;

go的异步由开启goroutine实现,go程是独立运行的执行单元,而处理异步任务中的同步操作,go有专门的sync包。

在过程式编程中,大多数程序的执行方式都是按照编码顺序,一步一步执行到程序结束。在早期cpu单核心时代,是没有真正的并发概念的,因为单核心cpu在同一时间只能执行一项任务,也就是串行执行。随着时代的发展,一颗cpu已经可以集成多个核心,这让cpu在同一时间并发执行多项任务有了物理基础。

2. 阻塞block

某个并发任务由于拿不到cpu资源没法工作,只能等待其他任务完成让出cpu资源。

3. 异步回调 async callback

A线程唤起B线程,令其独立执行,同时给B一个回调函数,命令B在干完活以后执行这个回调函数,这个回调函数会与A线程发生交互。

4. 进程 - 线程 - 协程
  • 进程

==进程是系统资源分配的最小单位==, 系统由一个个进程(程序)组成,
一般情况下,包括文本区域(text region)、
数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码,
数据区域存储变量和进程执行期间使用的动态分配的内存,
堆栈区域存储着活动过程调用的指令和本地变量。

进程间切换:
1.切换页目录以使用新的地址空间;
2.切换内核栈;
3.切换硬件上下文;

通信问题: 由于进程间是隔离的,各自拥有自己的内存内存资源, 因此相对于线程比较安全, 所以不同进程之间的数据只能通过 IPC(Inter-Process Communication) 进行通信共享。

  • 线程

==线程是程序执行流的最小单元==。一个标准的线程由线程ID,
当前指令指针(PC),寄存器集合和堆栈组成。线程属于进程,
线程共享进程的内存地址空间。

线程间切换:
1.切换内核栈
2.切换硬件上下文

通信问题: 进程相当于一个容器,而线程而是运行在容器里面的,因此对于容器内的东西,线程是共同享有的,因此线程间的通信可以直接通过全局变量进行通信,但是由此带来的例如多个线程读写同一个地址变量的时候则将带来不可预期的后果,因此这时候引入了各种锁的作用,例如互斥锁等。

  • 协程

==协程是属于线程的。协程程序是在线程里面跑的,因此协程又称微线程和纤程等。==
协没有线程的上下文切换消耗。协程的调度切换是用户(程序员)手动切换的,因此更加灵活,因此又叫用户空间线程。由于协程是用户调度的,所以不会出现执行一半的代码片段被强制中断了,因此无需原子操作锁。

5. 共享内存

在许多基于线程并发的语言中,共享内存是常见的做法,多个并发线程通过共享内存的方式交互数据,通常这会导致很多线程安全问题:AB间共享的数据地址可能被C并发修改。

6.同步锁/资源锁

为了解决共享内存所导致的线程安全问题,共享的内存地址在特定时间段被特定线程锁定,而加锁期间,其它线程却无法访问,这带来低效率问题。

7.死锁

A锁住B要的资源,B锁住A要的资源,AB同时阻塞。

8.线程池与线程并发

在多线程并发中,每个线程都抢占cpu资源,导致线程任务不断切换上下文,cpu也会分出部分算力处理线程调度。因此线程不是越多越好,为了避免无度创建线程(内存溢出OutOfMemory),一般在一个池中创建一堆线程,各任务循环利用这些线程,用完以后重置并丢回池中。

利:避免了无度创建线程,降低了OOM的风险
弊:用不用都占去了一大块内存开销

由此可见基于线程的并发是把双刃剑:首先开线程占内存, 啥也不干就拿走1M栈空间,1024条线程就占用1G内存;其次,线程切换占CPU的调度资源;再次,内存共享不安全,加了锁效率又低下;最后,有可能因为各种异步回调导致开发难度加大。

9.堆栈

堆和栈的概念非常容易造成混淆,根本原因是在计算机内存结构和软件编程中的数据结构都有相同的名称。

编程中数据结构的堆和栈:

栈:栈是一种先进后出的线性结构,可以使用数组或链表(单向链表、双向链表或循环链表)作为底层数据结构;
堆:堆是一种常用的树形结构,是一种特殊的完全二叉树,其底层数据结构都用数组;

计算机内存结构中的堆栈:

栈
    变量和对象的名称
    引用堆地址
堆
    杂乱无章地堆放各种数据
    没有栈对其进行引用时,就由nil进行引用
    被nil引用的堆地中的内容随时可能被垃圾回收器回收
垃圾回收
    一块堆内存如果没有被栈引用,就会被0号栈(空nil)所引用
    一切被nil引用的对内存,会随时被垃圾回收器(GarbageCollector=GC)回收
10. CSP并发模型

与共享内存的并发通信模型不同,CSP(CommunicatingSequentialProcess 可通信的序列化进程)模型是基于管道(channel)进行任务间的消息传递。Go就是根据CSP模型实现并发任务的通信。

共享内存 VS 通道
内存共享:通过内存共享通信
通道:通过通信共享内存

介绍完这些基础概念后,我们开始展开Go并发编程!

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

推荐阅读更多精彩内容

  • 必备的理论基础 1.操作系统作用: 隐藏丑陋复杂的硬件接口,提供良好的抽象接口。 管理调度进程,并将多个进程对硬件...
    drfung阅读 3,506评论 0 5
  • Go 并发编程 选择 Go 编程的原因可能是看中它简单且强大,那么你其实可以选择C语言;除此之外,我看中 Go 的...
    PRE_ZHY阅读 872评论 1 6
  • 概述 简而言之,所谓并发编程是指在一台处理器上“同时”处理多个任务。 随着硬件的发展,并发程序变得越来越重要。We...
    泡泡龙吐泡泡阅读 7,895评论 1 12
  • 转一篇驹神的关于异步编程和Asyncio的文章。这是上篇,共三篇。原文地址:http://aju.space/20...
    SeanCheney阅读 9,767评论 2 99
  • 轻量级线程:协程 在常用的并发模型中,多进程、多线程、分布式是最普遍的,不过近些年来逐渐有一些语言以first-c...
    Tenderness4阅读 6,350评论 2 10