一 . 协程
协程:是单线程下的并发,又称为微线程,协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
协程的优点:
1 . 协程的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级。
2 . 单线程内就可以实现并发的效果,最大限度地利用cpu .
协程的缺点:
1 . 协程的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程。
2 . 协程指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程。
协程的本质就是在单线程下,由用户自己控制了一个任务遇到IO阻塞了就切换另外一个任务去执行,从此来提升效率。协程可以控制多个任务之间的切换,切换之前将任务的状态保存下来,以便重新运行时,可以基于暂停的位置继续进行,也可以检测IO操作,在遇到IO操作的情况下才发生切换。
协程就是告诉Cpython解释器,我自己搞了一线程让你去执行, 省去你切换线程的时间,我自己切换比你切换要快很多,避免了很多的开销,对于单线程下,我们不可避免程序中出现IO操作,但如果我们能在自己的程序中(用户程序级别,非操作系统级别)控制单线程下的多个任务能在一个任务遇到IO阻塞时就切换到另外一个任务去计算,这样就保证了该线程能够最大限度地处于就绪状态,也就是随时都可以被cpu执行的状态,相当于我们在用户程序级别将自己的IO操作最大限度地隐藏起来,从而可以迷惑操作系统,让它看到:该线程好像是一直在计算,IO比较少,从而更多的将cpu的执行权限分配给线程。
Gevent,Gevent是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的模式是Greenlet,它是以C语言扩展模块形式接入python的轻量级协程,代码如下:
from gevent import monkey ; monkey . patch_all( )
import gevent # 直接导入模块
import time # 时间模块
def eat ( ) :
print("eat food 1")
time.sleep(2)
print("eat food 2")
def play ( ) :
print("play1")
time.sleep(1) # 来回切换,直到一个IO的时间结束
print(“play2")
g1 = gevent.spawn(eat)
g2 = gevent.spawn(play_phone)
gevent.joinall([g1,g2])
print("主")
二 . IO多路复用
IO多路复用包括1.阻塞IO 2.非阻塞IO 3. 多路复用IO 4. 异步IO
1 . 阻塞IO : 效率是比较低的, kernel准备数据,而network来说,很多时候数据在一开始还没有到达
但在用户进程这边,整个进程会被阻塞
2 . 非阻塞IO : 非阻塞的recvform系统调用之后,进程并没有被阻塞,内核返给了进程,如果数据没准备好,此时就会返回一个错误,进程在返回之后,可以干点别的事情,然后再发起recvform系统调用,循环往复。
3 . 多路复用IO (重点)
select 将所有需要监听的对象,放到一个列表里面,将这个列表交给select 来监听,凡是有动静的对象,直接给你返回一个列表中,然后我们循环这个列表,根据列表里面的有东京的对象,来进行对应的操作,window 和 linux
select 和 poll 内部在监听的所有对象的时候,是循环遍历的操作,挨个问一遍有没有数据
Epoll : linux 每个被监听的对象,都是通过回调机制来搞的,也就是,监听的列表对象里面的这个对象,凡是有动静,自行通知epoll ,然后epoll把这些有动静的对象返回
4 . 异步IO:最NB的,效率最高,因为将网络请求里面的两个IO时间都省了,这是C语言里面的东西