大家好,今天将梳理出的 Go语言并发知识内容,分享给大家。 请多多指教,谢谢。
本次《Go语言并发知识》内容共分为三个章节,本文为第一章节。
- Golang 基础之并发知识 (一)
- Golang 基础之并发知识 (二)
- Golang 基础之并发知识 (三)
本章节内容
- 什么是并发、并行?
- 什么是原子操作?
- 什么是并发锁?
- 什么是通道?
本章节将以上4个问题,展开介绍。
什么是并发、并行?
首先,我先介绍操作系统中几个相关的知识点:进程、线程、协程。
进程:进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。(在Linux系统中可以通过 ps -ef
命令查询)
线程:线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。(在Linux系统中可以通过 ps -efT
命令查询)
协程:独立的栈空间,共享堆空间,调度由用户自己控制,本质上有点类似于用户级线程,这些用户级线程的调度也是自己实现的。 (在系统中无法查看,只能从程序代码中查看)
一个进程可以创建和撤销多个线程。
一个线程上可以跑多个协程,协程是轻量级的线程。
并发介绍
并发主要体现在单核CPU上,以切换时间片来实现 “同时” 运行。
这里的同时并不是真正的,因为单核CPU无法做到让A、B、C三个线程在同时运行,只能通过来回切换方式运行。同一时刻只能运行一个实例。
并行介绍
并行主要体现在多核CPU上,则是利用多核实现同时运行。
当系统有一个以上CPU时,A、B、C进程在不同CPU (逻辑核)调度,各进程互不抢占CPU资源,可以同时进行。
并发的多个任务之间是互相抢占资源的。
并行的多个任务之间是不互相抢占资源的.
什么是原子操作?
**原子操作可以理解为:在进行过程中不能被中断的操作。**也就是说,针对某个值的原子操作在被进行的过程当中,CPU绝不会再去进行其它的针对该值的操作。无论这些其它的操作是否为原子操作都会是这样。
为了实现这样的严谨性,原子操作仅会由一个独立的CPU指令代表和完成。只有这样才能够在并发环境下保证原子操作的绝对安全。
Go语言提供的原子操作都是非侵入式的,它们由标准库代码包sync/atomic中的众多函数代表。
sync/atomic函数库的使用,将在后续go语言并发使用章节给大家介绍。
什么是并发锁?
举例
如果两个或者多个线程在没有互相同步情况下,访问某个共享的资源,并试图同时读和写这个资源,就处于相互竞争的状态,这种情况被称作竞争状态 (race candition)。 竞争状态的存在是让并发程序变得复杂的地方,十分容易引起潜在问题。对一个共享资源的读和写操作必须是原子化,可以理解为,同一时刻只能有一个 线程 对共享资源进行读和写的操作。
一种防止竞争状态的方法:使用锁机制,锁住共享资源,从而保证线程的同步状态。
这里简单介绍下 互斥锁 概念,互斥锁这个名字来自互斥(mutual exclusion)的概念,互斥锁用于在代码上创建一个临界区,保证同一个时间只有一个线程可以执行这个临界区代码。
扩展内容
死锁: 可以理解为完成一项任务的资源被两个(或多个)不同的协程分别占用了,导致它们全都处于等待状态不能完成下去。
活锁: 例如两个或多个协程在执行时分别占用了部分资源导致无法执行。于是他们都释放资源并重新请求,可是依旧碰撞,导致仍然无法执行。
饥饿: 表示在任何情况下,并发线程都无法获得执行所需的所有资源。
什么是通道?
channel的使用和介绍,已经在 Golang 基础之基础语法梳理 (二) 文章中介绍了,不了解的小伙伴可以前去观看。
基于之前文章,我在进行几点补充:
Go提供了一种称为通道的机制,通道(chan)是goroutine之间传递特定值的通信机制,用于在goroutine之间共享数据。当作为goroutine执行并发活动时,需要在goroutine之间共享资源或数据,通道充当goroutine之间的管道并提供一种机制来保证同步交换。
它属于通信顺序进程并发模式(Communicating sequential processes,CSP)。
Go语言中还有另一种并发模式,即共享内存多线程的传统模型 MPG。
以通信的手段来共享内存 — 是Go的一种重要特性,也是特有的机制。
goroutine 、并发同步模型CSP 等内容知识点,下章节为大家介绍
技术文章持续更新,请大家多多关注呀~~
搜索微信公众号,关注我【 帽儿山的枪手 】