golang笔记—— 进程\线程\协程\Goroutine

一、并发与并行

1. 并发

并发(Concurrent):1个CPU交错执行2个任务。单核系统中,进程(或线程)通过时间片或出让控制权来实现任务切换,以达到“同时”运行多个程序的目的,实际上任何时刻都只有1个任务被执行。宏观上是“同时”执行,微观上是交错地顺序执行。

并发的特性

  • 系统资源被多个进程(或线程)共享,造成程序结果不唯一
  • 进程(或线程)结果的多变,导致进程(或线程)运行会出现不同的结果或偶发的异常
  • 多个进程(或线程)间存在竞争资源产生的互斥关系,也存在协作完成一个整体任务产生的同步关系。

能否很好地解决多个进程(或线程)间的同步及互斥关系,将决定程序能否正常运行。

2. 并行

并行(Parallel):2个CPU分别同时各执行了1个任务。多核系统中,理想情况下,可以让多个进程(或线程)做到真正意义上的同时执行,它们之间不需要排队

通过下图中Erlang 之父 Joe Armstrong对并发与并行的说明,我们能清晰的区分并发与并行


二、进程、线程、协程

1. 进程

进程(Process):是操作系统进行资源分配和调度的一个独立单位。是一个具有特定功能的程序运行在一个数据集上的一次动态过程。是应用程序运行的载体。操作系统内核通过进程控制块(PCB,process control block)来感知进程。

进程的组成

  • 程序:用于描述进程要完成的功能,是控制进程执行的指令集。(进程的执行)
  • 数据集合:程序执行时所需的数据和工作空间。(进程的数据资源)
  • 进程控制块(PCB):但基本包括进程标识符,当前状态,现场保护区,存储指针,占用资源表以及进程优先级等信息。它是进程存在的唯一标志。(进程的详细信息)

进程的切换


进程切换,就是把进程存放在处理器的寄存器中的中间数据存放到进程的私有堆栈中,从而把处理器的寄存器腾出来让其他进程使用。这个中间数据,就被称作该进程的上下文。进程的切换实质上就是被中止运行进程与待运行进程上下文的切换

进程的状态


就绪状态:进程已获得除处理器外的所需资源,等待分配处理器资源;只要分配了处理器进程就可执行。就绪进程可以按多个优先级来划分队列。
运行状态:占有CPU,在CPU上执行。
阻塞状态:由于进程等待某种条件(如I/O操作或进程同步),在条件满足之前无法继续执行。
创建状态:进程正在被创建,系统为其初始化PCB,分配资源。
终止状态:进程正在从系统中撤销,回收进程的资源,撤销其PCB。

进程的通信方式

  • 管道
    管道可以看成是一种只存在内存中,不存在于任何文件系统中的特殊文件,支持普通的read、write 等函数。分为以下两种管道
    匿名管道(pipe)
    半双工(即数据只能在一个方向上流动),具有固定的读端和写端,只能用于具有亲缘关系的进程之间的通信。
    命名管道(FIFO)
    半双工,有自己的名字和访问权限的限制,就像一个文件一样,它可以用于不相关进程间的通信,进程通过使用命名管道的名字获得管道。

    管道的特点:写满时,不能再写;读空时,不能再读
    使用场景:适合两个进程间发送非常短小的、频率很高的消息。

  • 消息队列
    由消息组成的链表,存放在内核中并由消息队列标识符标识。消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。

  • 信号
    信号是一种非常短的消息,短到只有一个数字。一个进程可以向另外一个进程或者另外一组进程发送信号消息,通知目标进程执行特定的代码

  • 信号量
    用于实现进程间的互斥与同步,而不用于存储进程间通信数据,是一种保证共享资源有序访问的工具。

  • 共享内存
    允许两个或多个进程共享一个给定的存储区,这一段存储区可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程。
    共享内存将保持到通信完毕为止,不会频繁解除内存映射或重建内存共享区域,因此共享内存的通信方式效率非常高。
    使用场景:适合多进程间共享的、非常庞大的、读写操作频率很高的数据通信。

  • 网络Socket
    网络环境中进程间通信的API。与其他通信机制不同的是,它可用于不同机器间的进程通信。
    使用场景:适用于分布式开发

2. 线程

线程(thread):是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。

线程的分类

线程的实现可以分为两类:

1)用户级线程(User-Level Thread)

由进程负责调度管理,不依赖于操作系统内核
优点:

  • 线程位于用户空间(即不需要模式切换)。
  • 完全控制线程调度器(例如:网站服务器)。
  • 独立于操作系统(线程可以在不支持它们的操作系统上运行)。
  • 运行时系统(run time system)可以切换用户空间中的本地阻塞线程(例如:等待另一个线程完成)。

缺点:

  • 系统调度中,对一个线程的阻塞将会导致整个进程阻塞(例如:当一个线程因 I/O 而处于等待状态时,整个进程就会被调度程序切换为等待状态,其他线程得不到运行的机会)。
  • 网站服务器中,一个页面的错误将导致整个进程阻塞。
  • 非真正意义的线程并行(一个进程安排在单个CPU上)。
  • 不存在时钟中断(例如,如果用户线程是非抢占式的,将无法被“进程调度”以round-robin的调度算法调用,因为round-robin调度算法中限制了cpu时间片)。
2)内核级线程(Kernel-Level Thread)

由操作系统支持和管理
优点:

  • 实现了真正意义上的线程并行。
  • 不需要运行时系统的参与。

缺点:
频繁的模式切换导致内核开支。

线程的同步

当多个线程同时读写同一份共享资源的时候,可能会引起冲突,这时候,我们需要引入线程“同步”机制。线程同步是为了防止多个线程同时访问同一个数据对象时,对数据造成破坏。线程的同步是保证多线程安全访问资源的一种手段。

主要通过临界区(Critical Section)、互斥对象(Mutex)的机制来实现互斥控制,在Java中分别对应synchornized及对象锁;通过信号量(Semaphore)、事件对象(Event)以通知的方式进行同步控制,在Java中分别对应wait()、notify()等方法。

也可以通过写时复制(Copy On Write)的无锁方式来实现线程的同步,即在每个线程中拷贝一份共享资源的副本。

线程的出现,是为了分离进程的两个功能:资源分配和系统调度。让更细粒度、更轻量的线程来承担调度,减轻调度带来的开销。但线程还是不够轻量,因为调度是在内核空间进行的,每次线程切换都需要陷入内核,这个开销还是不可忽视的。协程则是把调度逻辑在用户空间里实现,通过自己(编译器运行时系统/程序员)模拟控制权的交接,来达到更加细粒度的控制。
在操作系统的OS Thread和编程语言的User Thread之间,实际上存在3种线程对应模型,也就是:1:1,1:N,M:N。

  • 1:1:一个用户线程就只在一个内核线程上跑,这时可以利用多核,但是上下文切换很慢,切换效率很低。
  • N:1:多个(N)用户线程始终在一个内核线程上跑,context上下文切换很快,但是无法真正的利用多核。
  • M:N:多个用户线程在多个内核线程上跑,这个可以集齐上面两者的优势,既能快速切换上下文,也能利用多核的优势

3. 协程

协程(Coroutine):是一种用户级的轻量线程,拥有自己独立的栈和共享的堆,共享堆,不共享栈。协程由程序员在协程的代码里显示调度。进程、线程是操作系统级别的概念,而协程是编译器级别的,协程间切换只需要保存任务的上下文,没有内核的开销。
协程的优势

  • 内存占用少
  • 上下文切换代价小

4. goroutine

Goroutine基本概念

  • goroutine是Go语言运行库的功能,不是操作系统提供的功能,goroutine不是用线程实现的,而是go语言实现的用户态线程。
  • goroutine就是一段代码,一个函数入口,以及在堆上为其分配的一个堆栈。所以它非常廉价,我们可以很轻松的创建上万个goroutine,但它们并不是被操作系统所调度执行。
  • goroutine来自协程的概念,让一组可复用的函数运行在一组线程之上,即使有goroutine阻塞,该线程的其他goroutine也可以被runtime调度,转移到其他可运行的线程上。这更像是多线程和协程的综合体,能最大限度提升执行效率,发挥多核处理能力。

Goroutine特点

  • 占用内存更小(几kb)
  • 调度更灵活(runtime调度)

参考文档:
https://zhuanlan.zhihu.com/p/137339439
https://zhuanlan.zhihu.com/p/260830550
https://zhuanlan.zhihu.com/p/51194025
https://www.cnblogs.com/LUO77/p/5816326.html
https://blog.csdn.net/cafucwxy/article/details/78453430
https://blog.csdn.net/zhaohong_bo/article/details/89552188
https://www.coder55.com/article/11579
http://www.sizeofvoid.net/goroutine-under-the-hood/
https://zhuanlan.zhihu.com/p/68299348

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

推荐阅读更多精彩内容

  • 人是一种高并发的物种,细品。 初识 对 Go 语言的第一印象就是其原生地支持并发编程,而且使用的是协程,比线程更加...
    K8sCat阅读 36,910评论 0 1
  • 并发基础 在说Golang的并发编程之前,先认识一下目前并发的几种实现方式: 1.多进程。操作系统实现的并发模型,...
    睡着别叫醒我阅读 2,224评论 0 1
  • 看了一天的相关概念,很多涉及到操作系统与底层硬件层面,脑子有点晕,对自己所理解的东西清理一下并记录下来,有些不对的...
    寻找无双丶阅读 3,589评论 0 1
  • 1. 并行和并发 并行:在同一时刻,有多条指令在多个CPU处理器上同时执行 2个队伍,2个窗口,要求硬件支持 并发...
    陈光环_18阅读 260评论 0 0
  • 本文是在上一篇文章的基础上Golang之并发编程一的基础上的续篇,如果有兴趣的话,大家可以先看看上一篇的内容,也希...
    睡着别叫醒我阅读 345评论 0 0