4. 进程、线程以及协程间的区别
(1) 进程(process)
进程是系统进行资源分配和调度的一个独立的最小单位,它是程序执行的一个实例。
程序运行时,系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候,就会为它分配CPU、内存、时间片,程序开始真正运行。
进程拥有自己独立的内存空间,进程间数据不共享,因此开销大。
进程特征:
- 动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生的,动态消亡的;
- 并发性:任何进程都可以同其他进程一起并发执行。
- 独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位。
- 异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进。
(2) 线程(thread)
线程是程序执行的最小单位,它是进程的一个实体,也是进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本的单位。
一个程序至少有一个进程,一个进程至少有一个线程。一个进程可以由多个线程组成,线程不能够独立执行,必须依存在进程中。
线程间共享进程的所有资源(内存共享、数据共享、全局变量共享等),从而极大的提高了程序的运行效率,每个线程有自己的堆栈和局部变量。
线程的划分尺度小于进程(资源比进程少,仅仅需要运行中必不可少的程序计数器、寄存器和栈),使得多线程程序的并发性高。
线程执行开销小,但不利于资源管理和保护,而进程刚好相反。
(3) 协程(coroutine)
协程是一种用户态的轻量级线程,也称微线程,协程的调度完全由用户控制。
协程拥有自己的寄存器上下文和栈,协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
在合适的实际,gevent实现的协程可以把一个协程切换到另一个协程。只要这个过程中保存或回复CPU上下文那么程序还是可以运行的。
通俗解释:在一个线程中的某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另外一个函数中执行,注意不是通过调用函数的方式做到的,并且且换的次数以及什么时候再切换到原来的函数都由开发者自己去确定。
协程是程序级别的,由程序员根据需要自己调度。我们把一个线程中的一个个函数叫做子程序,那么子程序在执行过程中可以中断去执行别的子程序;别的子程序也可以中断回来继续执行之前的子程序,这就是协程。
(4) 协程的优缺点
-
协程的优点
- 无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能(但也失去了标准线程使用多CPU的能力,需要用户自己控制调度);
- 无需原子操作锁定及同步的开销;
- 方便切换控制流,简化编程模型;
- 协程很适合用于高并发处理,一个CPU支持上万的协程不是问题,高并发+高扩展性+低成本。
-
协程的缺点
- 无法利用多核资源,协程的本质是个单线程,它不能同时将单个CPU的多个核上,协程需要和进程配合才能运行在多个CPU上(CPU密集型应用)。
- 进行阻塞操作时,会阻塞掉整个程序。
(5) 进程和线程的区别和优劣
-
进程是资源分配的最小单位,线程是程序执行的最小单位;
-
进程有自己独立的地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,耗费资源多;而线程是共享进程间的资源,使用相同的地址空间,因此CPU 切换和创建一个线程的开销比进程小很多。
-
线程之间的通信更方便,统一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信的方式进行,不过如何处理好同步与互斥是编写多线程程序的难点。
-
多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,因为所有线程共享进程的内存;而一个进程死掉并不会对别的进程造成影响,因为进程有独立独立的地址空间,著名的Apache最早就是采用多进程的模式,现在好像使用的是多进程+多线程的混合模式。
(6) 协程和线程的差异
- (1) 在实现多任务时,线程切换从系统层面远不止保存和恢复cpu上下文这么简单。
- (2) 操作系统为了程序运行的高效性,每个线程都有自己缓存Cache等数据,操作系统会自动实现数据恢复操作,所以线程切换非常耗性能。
- (3) 协程切换只是单纯的操作CPU上下文,所以一秒秒钟切换上百万次系统都扛得住。