""" 协程 """ ''' 协程: 类似于一个可以暂停的函数,可以多次传入数据,可以多次返回数据 协程是可交互的 耗资源大小:进程 --> 线程(微进程) --> 协程(微线程) 协程完成通信:生产者与消费者模式--(进程/线程/协程间通信)都可实现 进程/线程/协程 三者之间的关系: 多进程是重开进程 多线程是在进程中开启 协程是在一个进程中的一个线程中开启 协程的执行单元就是函数,(从执行单元上属于并发,对于整个服务器来说并不是) 如果协程阻塞,那么整个进程(线程)也会被阻塞。任意时刻只有一个协程在执行 协程不能避开阻塞, 通过异步的方式避开阻塞 ''' from random import randint from time import sleep def producer(generator): while True: task = randint(1, 100) generator.send(task) print('生产了一个任务:', task) sleep(2) def consumer(): while True: task = (yield) print('消费了一个任务:', task) if __name__ == '__main__': generator = consumer() next(generator) # 启动生成器, 是consumer阻塞在yield, 才能执行producer中的send方法 producer(generator)
greenlet: 原生的协程包 pip3 install greenlet
价值一:高性能的原生协程
价值二:语义更加明确的显示切换
价值三:直接将函数包装成协程,保持代码风格
''' greenlet协程 ''' from greenlet import greenlet from random import randint def producer(): """ 生产者 """ while True: item = randint(1, 100) c.switch(item) # 阻塞并 (转换发送数据)到consumer print('生产了一个任务:', item) def consumer(): """ 消费者 """ while True: item = p.switch() # 阻塞并转换到producer print('消费了一个任务:', item) if __name__ == '__main__': p = greenlet(producer) c = greenlet(consumer) c.switch() # 启动consumer ''' switch转换工作单元(函数producer和consumer) '''
gevent:
gevent = epoll(可避开阻塞) + greenlet(不可避开阻塞)
价值一:使用基于epoll的libev来避开阻塞
价值二:使用基于greenlet的高效协程来切换执行
价值三:只有遇到阻塞的时候切换,没有轮询的开销,也没有线程的开销
""" gevent = epoll(可避开阻塞) + greenlet(不可避开阻塞) """ from gevent import monkey; monkey.patch_all() # 猴子补丁, 将socket替换成epoll封装的socket from gevent.queue import Queue # gevent封装的队列 from random import randint from time import sleep import socket import gevent def producer(): while True: item = randint(0, 100) queue.put(item) print('生产了一个任务:', item) sleep(1) def consumer(): while True: item = queue.get() print('消费了一个任务:', item) sleep(3) def my_worker(): while True: conn, addr = server.accept() recv_data = conn.recv(1024) if recv_data: conn.send(recv_data) else: conn.close() break server = socket.socket() server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind(('', 8000)) server.listen(1000) queue = Queue(3) p = gevent.spawn(producer) # 协程化 c = gevent.spawn(consumer) # 等待所有协程结束 gevent.joinall( [p, c] )