目录

  • 一、并发编程
    • 1 - 并行和并发
    • 2 - 程序、进程、线程
    • 3 - 进程并发
    • 4 - 线程并发
    • 5 - 线程同步
  • 二、协程Coroutine
    • 1 - 协程概念
    • 2 - Go并发
    • 3 - go程创建
    • 4 - Goroutine特性
    • 5 - runtime包
    • 6 - go程嵌套特性

一、并发编程

1 - 并行和并发

  • 并发编程概述:简而言之,所谓并发编程是指在一台处理器上“同时”处理多个任务
  • 并行(parallel):指在同一时刻,有多条指令在多个处理器上同时执行
  • 并发(concurrency):指在同一时刻只能有一条指令执行,但多个进程指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,通过cpu时间片轮转使多个进程快速交替的执行
    • 宏观的并发是指在一段时间内,有多个程序在同时运行【用户体验上,程序在并行执行】
    • 并发在微观上,是指在同一时刻只能有一条指令执行,但多个程序指令被快速的轮换执行,使得在宏观上具有多个进程同时执行的效果,但在微观上并不是同时执行的,只是把时间分成若干段,使多个程序快速交替的执行【多个计划任务,顺序执行。在飞快的切换。轮换使用 cpu 时间轮片】
  • 咖啡机理解并行与并发
    • 并行是两个队列同时使用两台咖啡机 (真正的多任务)
    • 并发是两个队列交替使用一台咖啡机 ( 假 的多任务)

2 - 程序、进程、线程

  • 什么是程序:程序,是指编译好的二进制文件,在磁盘上,不占用系统资源(cpu、内存、打开的文件、设备、锁…)
  • 什么是进程:进程,是一个抽象的概念,与操作系统原理联系紧密。进程是活跃的程序,占用系统资源。在内存中执行。(程序运行起来,产生一个进程)
  • 进程状态:进程基本的状态有5种。分别为初始态,就绪态,运行态,挂起态与终止态。其中初始态为进程准备阶段,常与就绪态结合来看

3 - 进程并发

  • 进程并发:在操作系统中,可以产生很多的进程。在unix/linux系统中,正常情况下,子进程是通过父进程fork创建的,子进程再创建新的进程;在使用进程 实现并发时会出现什么问题呢?

    • 系统开销比较大,占用资源比较多,开启进程数量比较少
    • 在unix/linux系统下,还会产生“孤儿进程”和“僵尸进程”
  • 孤儿进程:父进程先于子进程结束,则子进程成为孤儿进程,子进程的父进程成为init进程,称为init进程领养孤儿进程
  • 僵尸进程:进程终止,父进程尚未回收,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程

4 - 线程并发

  • 什么是线程:LWP -> light weight process 轻量级的进程,本质仍是进程 (Linux下)

    • 进程:独立地址空间,拥有PCB
    • 线程:有独立的PCB,但没有独立的地址空间(共享)
    • 区别:在于是否共享地址空间。独居(进程);合租(线程)。
      • 线程:最小的执行单位
      • 进程:最小分配资源单位,可看成是只有一个线程的进程

Windows系统下,可以直接忽略进程的概念,只谈线程。因为线程是最小的执行单位,是被系统独立调度和分派的基本单位。而进程只是给线程提供执行环境。所以我们要更关注线程

  • 什么是PCB:为了描述控制进程的运行,系统中存放进程的管理和控制信息的数据结构称为进程控制块(PCB Process Control Block),它是进程实体的一部分,是操作系统中最重要的记录性数据结构。它是进程管理和控制的最重要的数据结构,每一个进程均有一个PCB,在创建进程时,建立PCB,伴随进程运行的全过程,直到进程撤消而撤消

    • PCB中记录了操作系统所需的,用于描述进程的当前情况以及控制进程运行的全部信息。PCB的作用是使一个在多道程序环境下不能独立运行的程序(含数据),成为一个能独立运行的基本单位,一个能与其他进程并发执行的进程。或者说,OS是根据PCB来对并发执行的进程进行控制和管理的。例如,当OS要调度某进程执行时,要从该进程的PCB中查出其现行状态及优先级;在调度到某进程后,要根据其PCB中所保存的处理机状态信息,设置该进程恢复运行的现场,并根据其PCB中的程序和数据的内存始址,找到其程序和数据;进程在执行过程中,当需要和与之合作的进程实现同步,通信或者访问文件时,也都需要访问PCB;当进程由于某种原因而暂停执行时,又须将器断点的处理机环境保存在PCB中。可见,在进程的整个生命期中,系统总是通过PCB对进程进行控制的,即系统是根据进程的PCB而不是任何别的什么而感知到该进程的存在的。所以说,PCB是进程存在的唯一标志
  • CPU抢占

5 - 线程同步

  • 同步概念:同步即协同步调,按预定的先后次序运行
  • 为什么需要同步:多个线程,共同操作一个共享资源的时候,就需要同步
    • “同步”的目的,是为了避免数据混乱,解决与时间有关的错误。实际上,不仅线程间需要同步,进程间、信号间等等都需要同步机制
  • 线程同步实现方式:互斥量mutex、读写锁
  • 互斥量mutex:Linux中提供一把互斥锁mutex(也称之为互斥量);每个线程在对资源操作前都尝试先加锁,成功加锁才能操作,操作结束解锁;资源还是共享的,线程间也还是竞争的,但通过“锁”就将资源的访问变成互斥操作,而后与时间有关的错误也不会再产生了
    • 注意:同一时刻,只能有一个线程持有该锁
    • 互斥锁实质上是操作系统提供的一把“建议锁”(又称“协同锁”),建议程序中有多线程访问共享资源的时候使用该机制。但,并没有强制限定(因此,即使有了mutex,如果有线程不按规则来访问数据,依然会造成数据混乱)
  • 读写锁
    • 与互斥量类似,但读写锁允许更高的并行性。其特性为:写独占,读共享;读写锁非常适合于对数据结构读的次数远大于写的情况
    • 读写锁也叫共享-独占锁。当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,它是以独占模式锁住的。写独占、读共享。
  • 读写锁状态:读写锁只有一把,但其具备两种状态
    • 读模式下加锁状态 (读锁)
    • 写模式下加锁状态 (写锁)
  • 读写锁特性
    • 读写锁是“写模式加锁”时, 解锁前,所有对该锁加锁的线程都会被阻塞
    • 读写锁是“读模式加锁”时, 如果线程以读模式对其加锁会成功;如果线程以写模式加锁会阻塞
    • 读写锁是“读模式加锁”时, 既有试图以写模式加锁的线程,也有试图以读模式加锁的线程。那么读写锁会阻塞随后的读模式锁请求。优先满足写模式锁。读锁、写锁并行阻塞,写锁优先级高(当同时有写线程和读线程时,优先写锁)

二、协程Coroutine

1 - 协程概念

  • 协程Coroutine:也叫轻量级线程

    • 与传统的系统级线程和进程相比,协程最大的优势在于“轻量级”。可以轻松创建上万个而不会导致系统资源衰竭。而线程和进程通常很难超过1万个。这也是协程别称“轻量级线程”的原因
    • 一个线程中可以有任意多个协程,但某一时刻只能有一个协程在运行,多个协程分享该线程分配到的计算机资源
    • 在协程中,调用一个任务就像调用一个函数一样,消耗的系统资源最少!但能达到进程、线程并发相同的效果
    • 在一次并发任务中,进程、线程、协程均可以实现。从系统资源消耗的角度出发来看,进程相当多,线程次之,协程最少
  • 进程、线程、协程都可以完成并发
    • 进程 -> 稳定性强
    • 线程 -> 节省资源
    • 协程 -> 效率高

2 - Go并发

  • Go并发

    • Go在语言级别支持协程,叫goroutine。Go 语言标准库提供的所有系统调用操作(包括所有同步IO操作),都会出让CPU给其他goroutine。这让轻量级线程的切换管理不依赖于系统的线程和进程,也不需要依赖于CPU的核心数量
    • 有人把Go比作21世纪的C语言。第一是因为Go语言设计简单,第二,21世纪最重要的就是并行程序设计,而Go从语言层面就支持并行。同时,并发程序的内存管理有时候是非常复杂的,而Go语言提供了自动垃圾回收机制
    • Go语言为并发编程而内置的上层API基于顺序通信进程模型CSP(communicating sequential processes)。这就意味着显式锁都是可以避免的,因为Go通过相对安全的通道发送和接受数据以实现同步,这大大地简化了并发程序的编写
  • Go语言中的并发程序主要使用两种手段:goroutine和channel
  • 什么是Goroutine
    • goroutine是Go并行设计的核心。goroutine说到底其实就是协程,它比线程更小,十几个goroutine可能体现在底层就是五六个线程,Go语言内部帮你实现了这些goroutine之间的内存共享。执行goroutine只需极少的栈内存(大概是4~5KB),当然会根据相应的数据伸缩。也正因为如此,可同时运行成千上万个并发任务。goroutine比thread更易用、更高效、更轻便
    • 一般情况下,一个普通计算机跑几十个线程就有点负载过大了,但是同样的机器却可以轻松地让成百上千个goroutine进行资源竞争

3 - go程创建

  • Goroutine的创建:(创建于进程中)只需在函数调用语句前添加 go 关键字,就可创建并发执行单元。开发人员无需了解任何执行细节,调度器会自动将其安排到合适的系统线程上执行
package mainimport ("fmt"
)func sing() {for i := 0; i < 50; i++ {fmt.Println("----正在唱:隔壁泰山----")}
}func dance() {for i := 0; i < 50; i++ {fmt.Println("----正在跳舞:赵四街舞----")}
}func main() {go sing()go dance()for {;}
}

4 - Goroutine特性

  • Goroutine特性:主goroutine退出后,其它的工作goroutine也会自动退出(主go程结束,相当于进程结束了,而go程是进程创建的,所以其他的go程也会退出)
func main() {go func() { // 创建一个 子go 程for i := 0; i < 5; i++ {fmt.Println("------I'm goroutine -------")time.Sleep(time.Second)}}()fmt.Println("------I'm main-------")for i := 0; i < 5; i++ { // 主 go 程fmt.Println("------I'm main-------")time.Sleep(time.Second)if i == 2 {break}}
}
/* 调试输出
------I'm main-------
------I'm main-------
------I'm goroutine -------
------I'm goroutine -------
------I'm main-------
------I'm goroutine -------
------I'm main-------
*/

5 - runtime包

  • runtime.Gosched():用于让出CPU时间片,让出当前goroutine的执行权限,调度器安排其他等待的任务运行,并在下次再获得cpu时间轮片的时候,从该出让cpu的位置恢复执行

    • 有点像跑接力赛,A跑了一会碰到代码runtime.Gosched() 就把接力棒交给B了,A歇着了,B继续跑
  • 下列代码执行分析
    • 没有runtime.Gosched()时,"main test"的打印还会出现比较连续的
    • 使用了runtime.Gosched()时,"main test"的打印就不会那么连续了,一次打印后就出让CPU了
func main() {go func() {for {fmt.Println(" this is goroutine test")}}()for {runtime.Gosched() // 出让当前 cpu 时间片fmt.Println(" this is main test")}
}
  • Goexit:调用 runtime.Goexit() 将立即终止当前 goroutine 执行,调度器确保所有已注册 defer延迟调用被执行
  • return和Goexit区别
    • return:返回当前函数调用到调用者那里去;return之前的defer注册都生效
    • Goexit:结束调用该函数的当前go程;Goexit之前的defer注册都生效
package mainimport ("fmt""runtime"
)func test() {defer fmt.Println("ccccccccccccccccc")//returnruntime.Goexit() // 退出当前go程。defer fmt.Println("ddddddddddddddddd")
}func main() {go func() {defer fmt.Println("aaaaaaaaaa")test()fmt.Println("bbbbbbbbbbbbb")}()for {;}
}
  • GOMAXPROCS:设置当前进程使用的最大cpu核数

    • 调用 runtime.GOMAXPROCS() 用来设置可以并行计算的CPU核数的最大值,并返回之前的值
package mainimport ("fmt""runtime"
)func main() {fmt.Println(runtime.GOROOT())n := runtime.GOMAXPROCS(1) //将cpu设置为 单核fmt.Println("n = ", n)n = runtime.GOMAXPROCS(2) //将cpu设置为 双核fmt.Println("n = ", n)for {go fmt.Print(0) // 子go 程fmt.Print(1) // 主 go 程}
}

6 - go程嵌套特性

  • aaa的go程是由匿名go程创建的:执行完“----2”的打印,匿名go程就退出了,但是aaa的go程并没有退出
package mainimport ("fmt""runtime""time"
)func aaa() {for {time.Sleep(time.Millisecond * 200)fmt.Println("-----------")}
}
func main() {go func() {fmt.Println("------------1")go aaa()fmt.Println("------------2")return}()for {runtime.GC()}
}

3-Go并发编程与协程Goroutine相关推荐

  1. python并发编程之协程

    python并发编程之协程 1.协程: 单线程实现并发 在应用程序里控制多个任务的切换+保存状态 优点: 应用程序级别速度要远远高于操作系统的切换 缺点: 多个任务一旦有一个阻塞没有切,整个线程都阻塞 ...

  2. python并发编程:协程asyncio、多线程threading、多进程multiprocessing

    python并发编程:协程.多线程.多进程 CPU密集型计算与IO密集型计算 多线程.多进程与协程的对比 多线程 创建多线程的方法 多线程实现的生产者-消费者爬虫 Lock解决线程安全问题 使用线程池 ...

  3. Go 分布式学习利器(17)-- Go并发编程之协程机制:Grountine 原理及使用

    文章目录 1. Thread VS Groutine 2. Groutine 调度原理 3. Groutine 示例代码 关于Go的底层实现还需要后续持续研究,文中如有一些原理描述有误,欢迎指证. 1 ...

  4. python并发之协程_python并发编程之协程

    一 引子 本节的主题是基于单线程来实现并发,即只用一个主线程(很明显可利用的cpu只有一个)情况下实现并发,为此我们需要先回顾下并发的本质:切换+保存状态 cpu正在运行一个任务,会在两种情况下切走去 ...

  5. Java并发编程实战~协程

    Golang 是一门号称从语言层面支持并发的编程语言,支持并发是 Golang 一个非常重要的特性.在上一篇文章<44 | 协程:更轻量级的线程>中我们介绍过,Golang 支持协程,协程 ...

  6. Golang并发编程-GPM协程调度模型原理及组成分析

    文章目录 一.操作系统的进程和线程模型 1.1.基础知识 1.2.KST/ULT 二.Golang的GPM协程调度模型 三.M的结构及对应关系 四.P的结构及状态转换 五.G的结构及状态转换 六.GP ...

  7. go 怎么等待所有的协程完成_GO语言基础进阶教程:Go语言的协程——Goroutine

    Go语言的协程--Goroutine 进程(Process),线程(Thread),协程(Coroutine,也叫轻量级线程) 进程进程是一个程序在一个数据集中的一次动态执行过程,可以简单理解为&qu ...

  8. golang协程goroutine

    协程goroutine 概念 协程(英语:coroutine)是计算机程序的一类组件,推广了协作式多任务的子例程,允许执行被挂起与被恢复.相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那 ...

  9. 从根上理解高性能、高并发(五):深入操作系统,理解高并发中的协程

    本文原题"程序员应如何理解高并发中的协程",转载请联系作者. 1.系列文章引言 1.1 文章目的 作为即时通讯技术的开发者来说,高性能.高并发相关的技术概念早就了然与胸,什么线程池 ...

最新文章

  1. java解析kafkaavro_如何使用Spring Kafka读取合并模式注册的AVRO消息?
  2. Swift 4 无限滚动轮播图(UICollectionView实现)
  3. Android的多任务之路
  4. 基于javafx的五子棋_基于JavaFX的SimpleDateFormat演示程序
  5. 基于matlab的图像分割,基于MATLAB的图像分割算法研究毕业论文
  6. db设计专用excel_独家|自卸车如何实现侧板结构快速设计,减少重复工作?
  7. 站内搜索(ELK)之数据表字典类型字段的索引思路
  8. 《Python算法教程_中文版》pdf
  9. 黑马程序员--Mysql中文乱码解决办法
  10. npm run build时报错“caniuse-lite is outdated”
  11. 13.爬虫训练场集成文件采集案例,来学习一下怎么实现的
  12. 阿里云飞天系统的技术架构(转)
  13. windows主机加固(2)
  14. CentOS7.6(1810)安装
  15. Hanselminutes播客55-MonoRail作为替代ASP.NET
  16. 使用Oh-My-Posh美化FluentTerminal
  17. 沈阳地铁线程规划图(地铁1号 -- 地铁5号)
  18. 七、加载3d tiles模型
  19. 2048经典版震撼来袭,多种游戏模式,三种布局,来迎接挑战吧!
  20. 60道Python常见面试题,做对80% Offer任你挑!

热门文章

  1. python爬虫之创建表格
  2. AXI4协议学习:架构、信号定义、工作时序和握手机制
  3. Linux系统重装出现c0409a9f,自学IT吧论坛Linux系统运营系列视频教程#28期2016系统/服务器资源天地 - www.zxit8.com...
  4. 统计学习导论之R语言应用(三):线性回归R语言代码实战
  5. html与css编程证书,利用CSS布局做一个简单的荣誉证书(代码示例)
  6. 解决在EasyUI中使用百度地图出现不居中和坐标图标显示异常的问题(红色代码部分)
  7. xposed检测方法
  8. Spring Boot 框架学习笔记(五)( SpringSecurity安全框架 )
  9. POI获取单元格颜色与设置单元格颜色
  10. 三口烧瓶规格有哪些_什么是三口烧瓶,应该如何制作 | | 化工资讯网