初始化进程、线程与协程的概念
什么是进程?
进程,是计算机中的程序关于某数据集合上的一次运行活动(白话来说就是执行中的程序就是进程),是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
什么是线程?
线程,有时候被称为轻量级进程,是程序执行流的最小单元。我们可以理解为,线程是属于进程的,多线程与单线程的区别在于多线程可以同时处理多个任务,这时候我们可以理解为多线程和多进程是一样的,我可以在我的进程中开启一个线程方音乐,同时也可以开启力另外的线程聊qq,但是进程之间的内存独立,而属于同一个进程的多个线程之间的内存是共享的,多个线程可以直接对它们所在进程的内存数据进行读写并且在线程间进行交换。
进程与线程的关系
线程属于进程,一个进程至少包含一个线程,可以包含多个线程,一个进程的内存空间是共享的,进程内的线程共享进程的内存空间,线程在使用共享内存时,同一时间内只有一个线程能使用这个共享内存,其他的线程必须等到当前线程结束后才能使用这一共享内存。
python线程的传说
python界一直有一个古老的传说,那就是python的多线程是鸡肋,那么这个传说的可信度到底有多少?如果我们做的是一个CPU密集型的程序(涉及到大量的计算),多线程的代码极有可能就是线性执行的,所以这种情况下多线程确实是鸡肋,因为它的效率极有可能还不如单线程,因为有context switch(其实就是线程之间的切换和线程的创建等等都是需要消耗时间的),但是如果是IO密集型,多线程可以明显提高效率。例如制作爬虫,绝大多数时间爬虫是在等待socket返回数据。这个时候C代码里有release GIL的,最终结果是某个线程等待IO的时候其它线程可以继续执行。
那么,为什么我们大python会这么不智能呢?我们都知道,python是一种解释性语言,在python执行的过程中,需要解释器一边解释一边执行,我们之前也介绍了,同一个进程的线程之间内存共享,那么就会出现内存资源的安全问题,python为了线程安全,就设置了全局解释器锁机制,既一个进程中同时只能有一个线程访问cpu。作为解释型语言,python能引入多线程的概念就已经非常不易了,目前看到的资料php和perl等多线程机制都是不健全的。解释型语言做多线程的艰难程度可以想见。。。具体下面的链接推荐:python的最难问题。
正是由于python多线程的缺陷,我们在这里需要引入协程的概念。
什么是协程
协程是一种用户态的轻量级线程。如果说多进程对于多CPU,多线程对应多核CPU,那么事件驱动和协程则是在充分挖掘不断提高性能的单核CPU的潜力。我们既可以利用异步优势,又可以避免反复系统调用,还有进程切换造成的开销,这就是协程。协程也是单线程,但是它能让原来要使用异步+回调方式写的非人类代码,可以用看似同步的方式写出来。它是实现推拉互动的所谓非抢占式协作的关键。对于python来说,由于python多线程中全局解释器导致的同时只能有一个线程访问cpu,所以对协程需求就相比于其他语言更为紧迫。
协程最大的优势就是协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
因为协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可获得极高的性能。
进程、线程与协程
从硬件的发展来看,从最初的单核单CPU,到单核多CPU,多核多CPU,似乎已经到了极限了,但是单核CPU性能却还在不断提升。server端也在不断的发展变化。如果将程序分为IO密集型应用和CPU密集型应用,二者的server的发展如下:
IO密集型应用: 多进程->多线程->事件驱动->协程
CPU密集型应用:多进程-->多线程
调度和切换的时间:进程 > 线程 > 协程