-
进程:进程就是应用程序的启动实例,比如说打开一个软件,打开一个应用,就等于开启一个进程。进程拥有代码和打开的文件资源,数据资源,独立的内存空间。
-
线程:从属于进程,是程序的执行者,一个进程至少包括一个主线程。当然也可以包含更多的子线程。线程有自己的栈空间。
-
协程:一种比线程更加轻量级的存在,正如一个进程下有多个线程一样,一个线程下可以拥有多个协程。协程是认为开启的,不受操作系统的管理和调度。这也就是说协程不会像线程那样切换上下文环境,消耗资源。
-
归纳:
对于操作系统来讲,线程是最小的执行单位,进程是最小的资源管理单位,协程是人为控制,不受操作系统的管理和调度。
-
多进程之间的通信
- 定义生产者/消费者模型
- 生产者写入数据到队列中,当队列容量已满的时候(限定队列长度),生产者属于阻塞状态。
- 消费者监听同步队列,当队列中有数据时需要拉取数据,否则就属于阻塞状态。
-
多线程之间的通信
-
为什么需要线程通信?
在多线程并发操作时,cpu默认是是随机切换线程的,如果我们使用多线程来共同完成一件任务时,我们希望他们有规律的执行,而不至于多个线程对于同一共享数据的读写操作。所以多线程之间时需要一个协调机制的。
-
怎么解决多线程通信问题
对于多线程避免多个线程对于同一共享数据的操作,我们引出锁的概念。python已经给我们提供了Threading.Lock() 对象,添加锁[lock.acquire()],一次只能加一把锁,加多了就会出现死锁状态。 释放锁 [lock.release()] .
Threading.Rlock() 对象,在同一线程内可以多次加锁[lock.acquire()] ,不会出现死锁状态。释放锁[lock.release()] ,加锁和释放锁需要成队的出现。
-
-
线程的生命周期
-
新建状态,当程序实例化一个对象时,就完成了新建的状态。
-
就绪状态,当创建的对象调用了start() 方法 则进入了就绪状态,start()方法是启动线程。
-
运行状态,当就绪状态的线程被CPU调度,开始执行run()方法,就进入了运行状态。
-
阻塞状态,当运行线程数大于处理器数的时候,运行状态的线程将会被阻塞,从而进入阻塞状态。
-
死亡状态,当run执行完程序块时,或者在run执行过程中抛出异常或者错误时,线程则进入死亡状态。
)
-
-
IO复用
-
select
-
原理
select是通过系统调用来监视着一个由多个文件描述符组成的数组,当select()返回后,数组中就绪的文件描述符会被内核修改标记位,使得进程可以获得这些文件描述符从而进行后续的读写操作。select是通过遍历来监视整个数组的,而且每次遍历都是线性的。
-
优点
select目前几乎在所有的平台上支持,良好的跨平台性。
-
缺点
- 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多的时候会很大。
- 单个进程能够监视的fd数量存在最大限制,在linux上默认为1024(可以通过修改宏定义或者重新编译内核的方式提升这个限制)
- 并且由于select的fd是放在数组中,并且每次都要线性遍历整个数组,当fd很多的时候,开销也很大。
-
-
poll
-
原理
poll本质上和select没有区别,只是没有了最大连接数(linux上默认1024个)的限制,原因是它基于链表存储的。
-
优点
没有最大连接数的限制
-
缺点
- 每次调用poll,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多的时候会很大。
- 并且由于poll的fd是放在数组中,并且每次都要线性遍历整个数组,当fd很多的时候,开销也很大。
-
-
epoll
- 原理
- 优点
- epoll的解决方法是每次注册新的事件到epoll中,会把所有的fd拷贝进内核,而不是在等待的时候重新拷贝,保证了每个fd在整个过程中只会拷贝1次。
- epoll没有这个限制,它所支持的fd上限是最大可以打开文件的数据,具体 数据可以cat /proc/sys/fs/file_max查看,一般来说这个数目和系统内存关系比较大。
- epoll的解决方法不像select和poll每次对所有fd进行遍历轮询所有fd集合,而是在注册新的事件时,为每个fd指定一个回调函数,当设备就绪的时候,调用这个回调函数,这个回调函数就会把就绪的fd加入一个就绪表中。所以epoll只需要遍历就绪表
- 水平触发:只要满足条件,就触发一个事件(只要有数据没有被获取,内核就不断通知你)。例如:在水平触发模式下,重复调用epoll.poll()会重复通知关注的event,直到与该even有关的所有数据都已被处理。
- 边缘触发:每当状态变化时,触发一个事件。例如:在边缘触发模式中,epoll.poll()在读或者写event在socket上发生后,将只会返回一次event。调用epoll.poll()的程序必须处理所有的和这个event相关的数据,随后的epoll.poll()调用不会再有这个event的通知。
-