整理自《go语言编程》-第四章
1、并发基础
多进程:多进程是在操作系统层面进行并发的基本模式。同时也是开销最大的模式。在Linux平台上,很过工具链正是采用这种模式在工作。比如某个Web服务器,它会有专门的进程负责网络端口的监听和链接管理,还会有专门的进程负责事务和运算。这种方法的好处在于简单、进程间互不影响,坏处是系统开销大,因为所有的进程都是由内核管理的。
多线程:多线程在大部分操作系统上都属于系统层面的并发模式,也是我们使用最多的最有效的一种模式。目前,我们所见的几乎所有工具链都会使用这种模式。它比多进程的开销小很多,但是其开销依旧比较大,且在高并发模式下,效率会有影响。
基于回调的非阻塞/异步IO:这种架构的诞生实际上来源于月多线程模式的危机。在很多高并发服务器开发实践中,使用多线程模式会很快耗尽服务器的内存和CPU资源。二这种模式通过事件驱动的方式使用异步IO,服务器持续运转,且尽可能少用线程,降低开销,它目前在Node.js中得到了很好的实践,但是使用这种模式,编程比多线程要复杂,因为它把流程做了分割,对于问题的本身反应不够自然。
协程:协程(coroutine)本质上一种用户态线程,不需要操作系统来进行抢占式调度,且在真正的实现中寄存于线程中,因此,系统开销极小,可以有效提高线程的任务并发性,而避免多线程的缺点。使用协程的优点是编程简单,结构清晰;缺点是需要语言的支持,如果不支持,则需要用户在程序中自行实现调度器。
2、协程
执行体是个抽象的概念,在操作系统层面有多个概念与之对应,比如操作系统自己掌握的进程(process)、进程内的线程(thread)以及进程内的协程(coroutine,也叫轻量级线程)
多数语言在语法层面并不直接支持协程,而是通过库的方式支持。
Go语言在语言级别支持轻量级线程,叫goroutine。
3、Goroutine
Goroutine是Go语言中的轻量级线程实现,由Go运行时(runtime)管理。
.go:关键字,函数调用前加go关键字,这次调用就会在一个新的goroutine中并发执行。当被调用的函数返回时,这个goroutine也自动结束。如果不是使用channel接收的话,这个函数的返回值将会被丢弃。
4、并发通信
不管是什么平台、什么编程语言并发都是一个大话题。
在工程上,有两种最常见的并发通信模型:共享数据和消息。
共享数据:多个并发单元分别保存对同一个数据的引用,实现对该数据的共享。被共享的数据可能有多种形式,比如内存数据块、磁盘文件、网络数据等。在实际工程应用中最常见的就是共享内存。
Go语言社区:不要通过共享内存来通信,而应该通过通信来共享内存。
Go语言提供的是另一种通信模型,即以消息机制而非共享内存作为通信方式。
5、Channel
(1)概念
Channel 是Go语言在语言级别提供的goroutine间的通信方式。我们可以使用channel在两个或多个goroutine之间传递消息。
Channel是进程内的通信方式,因此通过channel传递对象的过程和调用函数时参数
传递的行为比较一致,比如可以传递指针等。
Channel是类型相关的,一个channel只能传递一种类型的值。
(2)基本语法
声明形式:
Var chanName chan ElementType
例子:var ch chan int
定义channel:
Ch := make(chan int)
向channel中写入数据:
Ch <- value
从channel中读取数据:
Value := <- ch
(3)select
Go语言直接在语言级别支持select关键字,用于处理异步IO问题。
Select {
Case <- chan1:
//如果chan1成功读到数据,则进行该case处理语句
Case chan2 <-1:
//如果成功向chan2写入数据,则进行该case处理语句
Default:
//如果上面的都没有成功,则进入default处理流程
}
(4)缓冲机制
创建一个带缓冲区的channel:
C := make(chan int, 1024)
(5)超时机制
在并发编程的通信过程中,最需要处理的就是超时问题,即向channel写入数据时发现channel已满,或者从channel试图读取数据时发现channel为空。如果不正确处理这个问题,可能会导致整个goroutinue锁死。
Go语言没有提供直接的超时处理机制,但可以利用select机制,可以解决超时问题。
(6)channel的传递
注意:在go语言中channel本身也是一个原生类型,与map之类的类型地位一样,因此channel本身在定义后也可以通过channl来传递。
(7)单向channel
单向channel只能用于发送或者接收数据。
从设计者的角度,所有的代码都应该遵循“最小权限的原则”
(8)关闭channel
使用go语言的内置函数:close(ch)
在读取时使用多重返回值的方式可以判断: x, ok := <-ch
6、让出时间片
每个goroutine中控制何时主动让出时间片给其他goroutine,可以使用runtime包中的Gosched()函数实现。
7、同步
Go 语言包中的sync包提供两种锁类型:sync.Mutex 和sync.RWMutex.
8、全局唯一性操作
Go语言提供一个Once类型来保证全局唯一性操作。
有疑问加站长微信联系(非本文作者)