1.协程:又称微线程,纤程,可根据程序自身需要自己进行调度。
(1)在一个线程中会有很多函数(子程序),在子程序执行过程中可以中断去执行别的子程序,而别的子程序也可以中断回来继续执行之前的子程序,这个过程就称为协程。 同一线程内一段代码在执行过程中会中断然后跳转执行别的代码,接着在之前中断的地方继续开始执行
(2)进程>线程>协程 协程为系统最小运行单位
2.协程的优点:
(1)无需线程上下文切换的开销,协程避免了无意义的调度,由此可以提高性能(但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力)
(2)无需原子操作锁定及同步的开销
(3)方便切换控制流,简化编程模型
(4)高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
3.协程的缺点:
(1)无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上
(2)进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序
4.协程的实现(三种方式)
方式1
def consumer(name):
print('开始吃包子...')
while True:
print('\033[31;1m[consumer]%s需要包子\033[0m'%name)
bone = yield #接收send发送的数据
print('\033[31;1m[%s]吃了%s个包子\033[0m'%(name,bone))
def producer(obj1):
obj1.send(None) #必须先发送None
for i in range(3):
print('\033[32;1m[producer]\033[0m正在做%s个包子'%i)
obj1.send(i)
if __name__ == '__main__':
con1 = consumer('消费者A') #创建消费者对象
producer(con1)
方式2 greenlet模块实现协程
import greenlet
def A():
print('a.....')
g2.switch() #切换至B
print('a....2')
g2.switch()
def B():
print('b.....')
g1.switch() #切换至A
g3.switch()
print('b....2')
def C():
print("c......")
g2.switch()
g1 = greenlet.greenlet(A) #创建一个线程
g2 = greenlet.greenlet(B)
g3 = greenlet.greenlet(C)
g1.switch()
方式3 gevent模块实现协程
原理:gevent会主动识别程序内部的IO操作,当子程序遇到IO后,切换到别的子程序。如果所有的子程序都进入IO
import gevent
from gevent.event import Event
evt = Event()
def setter():
print('A: Hey wait for me, I have to do something')
gevent.sleep(3)
print("Ok, I'm done")
evt.set()
def waiter():
print("I'll wait for you")
evt.wait() # blocking
print("It's about time")
def main():
gevent.joinall([
gevent.spawn(setter),
gevent.spawn(waiter),
gevent.spawn(waiter),
])
if __name__ == '__main__': main()
5.事件驱动编程:一种编程规则
服务器处理模型的程序时,有以下几种模型:
(1)每收到一个请求,创建一个新的进程,来处理该请求;
优缺点:实现简单,但开销较大,导致服务器性能较差
(2)每收到一个请求,创建一个新的线程,来处理该请求;
优缺点:多线程在同一进程中运行,可能产生死锁问题
(3)每收到一个请求,放入一个事件列表,让主进程通过非阻塞I/O方式来处理请求(大多数网络服务器采用的方式)
优缺点:代码逻辑复杂,占用内存空间小,数据安全。