并发编程

“”“不要用共享内存的方法来通信,而是应该用通信的方法来共享内存。”""

这个议题太大了,现在仍在写作中…

进程、线程、协程

  当运行一个应用程序的时候,操作系统就会给这个应用程序启动一个进程。我们可以将进程看作一个包含应用程序在运行中需要用到的和维护的各种资源的容器。而一个进程至少包含一个线程,这个线程就是主线程。操作系统会调度线程到不同的 CPU 上执行,这个 CPU 不一定就是进程所在的 CPU。

进程 和 线程

进程(Process): 资源的所有权。

进程是一个具有一定独立功能的程序在一个数据集上的一次动态执行的过程,是操作系统进行资源分配和调度的一个基本单位,是应用程序运行的载体、是操作系统结构的基础。直白地讲,进程就是应用程序的启动实例。比如我们运行一个游戏,打开一个软件,就是开启了一个进程,进程拥有代码和打开的文件资源、数据资源、独立的内存空间。

进程具有的特征:

  • 动态性:进程是程序的一次执行过程,是临时的,有生命期的,是动态产生,动态消亡的;
  • 并发性:任何进程都可以同其他进行一起并发执行;
  • 独立性:进程是系统进行资源分配和调度的一个独立单位;
  • 结构性:进程由程序,数据和进程控制块三部分组成

线程(Thread): 执行和调度的基本单位

线程从属于进程,是程序的实际执行者。一个进程至少包含一个主线程,也可以有更多的子线程,线程拥有自己的栈空间。线程具有五种状态:

**对操作系统来说,线程是最小的执行单元,进程是最小的资源管理单元。**无论是进程还是线程,都是由操作系统来管理调度的。同一进程下的各线程共享资源,但不共享寄存器、栈、PC。

进程 + 线程

也许有人看懵了,就会有这样一个问题:线程是不是就是“进程的进程”呢?我们不如从以下几点看看。

进程和线程的区别:

  • 线程是程序执行的最小单位,进程是操作系统分配资源的最小单位。
  • 线程间互相独立,但同一进程下的线程共享进程的内存空间(代码段、数据集、堆等)以及一些进程级的资源(虚拟地址空间,文件描述符和信号处理等)。 线程在跨进程间互相不可见
  • 同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)
  • 在创建或撤销进程时,操作系统都要为之分配或回收资源,如内存空间、IO设备等。切换进程涉及到整个 CPU 的环境保存以及新被调度运行的 CPU 环境设置,而线程的切换只需要保存和设置少量寄存器的内容。
  • 进程之间并不会相互影响,但一个线程挂掉将导致整个进程挂掉。

线程间和进程间切换都有以下特点:

  • 都有各自可以共享的资源和不可共享的资源
  • 都要进行上下文切换
  • 在操作系统中都是通过抢占式时间片轮转方式工作,并且通过锁机制来协调冲突

*这个锁机制真是让人又爱又恨,它解决了信息不互通的 Workers 不礼貌地抢占空间和资源而带来的问题,却又带来了一个新的问题:死锁。抢占式时间片轮转同样拥有自己需要解决的问题,但关于这几点以后再聊。

那么进/线程之间是如何进行协作的呢?

进程间通信(Inter-Process Communication)主要包括管道、系统 IPC (包括队列、信号量、信号、共享内存等),以及套接字(Socket)这些又是什么东西呢?

管道就是在内核中开辟一块缓冲区,从一端往里塞,从另一端往外拿,就像你家下水管道(雾)

队列顾名思义,就是把要传递的信息排排队形成一个链表,先进先出。它和管道最大的差别是管道里的数据是无格式字节流 (就像下水道) ,而队列里是一个个不同的节点,可以承载不同格式。
最典型的例子就是“生产者/消费者”模式:

  • 若干个生产者向队列中写入数据
  • 若干个消费者从队列中消费数据
  • 通过锁机制控制队列和等待

关于信号量,就可以比作上厕所,每有一个进程占用了该资(cè)源(suǒ),它的信(kēng)号(wèi)量就少1。当信(kēng)号(wèi)量为0,那接下来想要用资(cè)源(suǒ)的就得在外面等着啦。

信号就更简单了,它向大家广播一则简短的消息。比如大家常见的就有 An enermy has been slained.

共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问;当一个进程更改了资源,所有进程都能察觉到更改。它是最快的IPC方式,但是十分不安全,没有做好防范措施就很容易导致程序崩溃。

协程(Coroutine)

协程是什么

协程(Coroutines)是一种比线程更加轻量级的存在,正如一个进程可以拥有多个线程一样,一个线程可以拥有多个协程。

协程不是被操作系统内核所管理的,而是完全由程序所控制,也就是在用户态执行。这样带来的好处是性能大幅度的提升,因为不会像线程切换那样消耗资源。

协程不是进程也不是线程,而是一个特殊的函数,这个函数可以在某个地方挂起,并且可以重新在挂起处外继续运行。所以说,协程与进程、线程相比并不是一个维度的概念。

协程的最大特点就是谦让性。

_drafts

task queue

  • goroutine-safe
  • store and pass values between goroutines
  • provide FIFO semantics
  • can cause goroutines to block and unblock

Goroutines: to execute tasks independently, potentially in parallel
channels: for communication, synchronization between goroutines

to use it, first we need to build it. we do that using the built-in make function

// buffered channel
ch := make(chan Task, 3)
Author: ZhouYingSASA
Link: http://zhouyingsasa.xyz/2020/11/16/Concurrency/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.