这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
一、锁
互斥锁是一种常用的控制共享资源访问的方法,它能够保证同时只有一个gotoutine可以访问共享资源,go语言使用sync包的Mutex类型来实现互斥锁,使用互斥锁能保证同一时间有且只有一个gotoutine进入临界区,其他的gotoutine则在等待锁。
互斥锁是完全互斥的,但是很多实际的场景下是读多写少的,我们并发读的时候不涉及资源修改的时候没必要枷锁,这种场景下使用读写锁是更好的一种选择,读写锁在go语言中使用sync包中的RWMutex类型
读写锁分为两种:读锁和写锁,当一个goroutine获取读锁之后,其他的gotoutine如果是获取读锁会继续获得锁,如果获取写锁就会等到,当一个goroutine获取写锁之后,gotoutine无论是获取读锁还是写锁都会等待。
需要注意的是读写锁适合读多写少的场景,如果读和写的操作差别不大,读写锁的优势不明显。
二、结构体
在Java中,我们已经体会过了面向对象的方便之处。我们只需要将现实中的模型抽象出来,就成为了一个类,类里面定义了描述这个类的一些属性。
而在Golang中,则没有对象这一说法,因为Golang是一个面向过程的语言。但是,又知道面向对象在开发中的便捷性,所以在Golang中有了结构体这一类型。
结构体是复合类型,当需要定义类型,它由一系列属性组成,每个属性都有自己的类型和值的时候,就应该使用结构体,它把数据聚集在一起。
组成结构体类型的那些数据成为字段(fields)。每个字段都有一个类型和一个名字;在一个结构体中,字段名字必须是唯一的。
三、协程与线程
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。
线程是指进程内的一个执行单元,也是进程内的可调度实体。线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。从技术的角度来说,“协程就是你可以暂停执行的函数”。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。