进程、线程与协程

  • 进程是cpu调度的基本单位
  • 线程是cpu调度的最小单位,一个进程至少有一个线程(主线程)
  • 协程不被操作系统内核所管理,完全由程序控制

名词解释

cpu 时间

操作系统包括程序,都需要在cpu内核上跑,它在同一时间内只能处理一个指令;
这时候就需要依赖对cpu运行时间的分配机制;
在早期的计算机上,并没有并发的概念,只能跑一个程序;
后面有进程的概念,可以同时跑多个进程,那么就需要对cpu的时间进行切片。
多个进程轮流使用,这个时间由操作系统来管理;
而操作系统本身也需要使用cpu,因此操作系统的优先级最高。
当一个指令的cpu时间用完了,要把执行权再交给操作系统。

内存

当操作系统启动之后,所有的内存都归操作系统管理;
操作系统启动之后要先有个loader(引导程序),再由这个loader把操作系统装载到内存去,整个内存归操作系统统一管理。
当有一个程序运行的时候,必然会消耗内存,操作系统要先给程序分配内存。
这个内存不会很大,在初始的时候需要多少内存就给它分配多少内存。
当程序在运行过程中需要处理大内存的时候,它要向操作系统申请内存,然后操作系统分配给它。
这时候操作系统要看内存够不够用,如果够用的话,就给它分配内存。
操作系统以进程为单位分配内存。

进程 Process

进程的目的就是担当分配系统资源(cpu时间、内存)的实体。
进程在操作系统的设计上就是用来让操作系统更好的调度cpu时间和内存资源的。
当一个程序运行起来的时候,它就是一个进程;
内核是个特殊的进程,它是操作系统被引导起来后第一个执行的程序。

线程 Thread

线程是操作系统能够进行运算的最小调度单位。

linux 一开始只支持进程,内核所提供的系统调用只能产生新的进程;
后面添加了对线程的支持,最早的线程支持来自于c语言的库(pthread),后面linux把它纳入自己的代码库中。
之后操作系统的系统调用给外部提供接口;
线程必须依附在进程上,一个进程里面至少要有一个线程,这个线程被称为主线程。
当主线程退出时,进程也随之退出了。
进程可以依附多个线程,这些线程也有cpu调度。
在linux里面还有内核线程,直接依赖与内核。

线程必须依赖进程,在进程里面是可以同时执行多个任务的,它是由线程实现的。

协程 Coroutine

协程是一种用户态的轻量级线程,无法利用多和资源。

协程是轻量级用户态线程,但协程不归操作系统管理。
程序跑在用户模式的时候叫做用户态,跑在内核上叫做内核态。
我们自己写的代码和一些库是用户态,如果调用了系统级别的东西,这时候就是内核态。

协程是属于用户态的,所以cpu不参与协程的调度,协程由我们自己去管理。

协程没办法利用多核,协程是依附在线程上的。
操作系统在调度线程和进程的时候是分时间片去调度的,分时间片是单核cpu。
如果是多核,也就是说一个进程下有两个线程的话,那么操作系统可能把两个线程分别放在两个cpu内核下去跑。
但是协程操作系统管不了,协程是第三方库实现的,要依附在线程上。
操作系统把线程放在内核上去跑了,协程跑什么操作系统不管,不会给协程分配cpu。

协程一般用户服务器编程。

I/O 密集型应用

发展过程: 多进程 -> 多线程 -> 事件驱动 -> 协程

I/O密集型主要处理文件或者网络;

cpu是一个独立的东西,在主板上。主板上还有其他的设备,比如说硬盘,网卡,usb驱动,接口模块。而cpu是主板上的一个元件。
cpu要通过I/端口和这些模块进行通讯(input/output)
I/O 密集型最大的I/O消耗就是处理文件和网络设备;
I/O 密集型对于前端来说就是针对网络的,并发指的是I/O;

最早是处理数据存储的,有了网络之后,就用来处理网络通讯。最早也是多进程方式进行处理,之后因为进程要比线程重很多,就用更多线程去处理了。

CPU 密集型

发展过程: 多进程 -> 多线程

CPU密集型主要是进行一系列的计算。

最早对于计算机的应用主要是cpu密集型,用于科学运算; 最早的计算机要尽可能的提高利用率,所有就有了分批处理。之后有了操作系统,就可以动态供多个用户使用计算机。 随着发展,后面cpu运算能力又提高了,就有了多线程。

调度和切换的时间: 进程 > 线程 > 协程

不管是多进程还是多线程,在进入切换时,都是有消耗的。这些消耗也是不能容忍的,之后就有了事件驱动,再往后就有了协程。

操作系统与进程、线程的关系

process

操作系统的设计可以归为三点:

  1. 以多进程形式,允许多个任务同时进行;
  2. 以多线程形式,允许单个任务分成不同的部分同时进行;
  3. 提供协调机制,一方面防止进程之间和线程之间发生冲突,另一方面允许进程和线程之间共享资源。

提个小问题

如果同时对一个文件进行读写操作,会怎么样呢?

  1. 在网卡之上,抽象出来一层I/O端口,再I/O之上又抽象了一层套接字端口;
  2. 要么就独占;
  3. 要么就加个锁;

共享内存也是一种加锁。

进程与线程的资源共享

thread
  1. 单线程进程的fork过程,将主线程的代码、数据、文件、寄存器状态、栈都复制多份。
  2. 多线程进程的fork过程,各个线程都拥有自己的寄存器状态和栈。共享进程中的代码、数据、文件。
Last Updated:
Contributors: kk