协程基础
底层实现
- 协程的底层是使用greenlet模块来实现的
from greenlet import greenlet def func1(): print("eat start")# 2 g2.switch() print("eat end")# 4 g2.switch() def func2(): print("play start")# 3 g1.switch() print("play end")# 5 g1 = greenlet(func1) g2 = greenlet(func2) g1.switch()# 1
介绍
- 当遇到IO操作时将程序切换到其他函数继续执行会提高CPU的利用效率
- 一个线程可以开启500个协程
- 更适用于网络操作中
安装
pip install gevent
应用
协程实现
from gevent import monkey;monkey.patch_all() # 将下面导入的所有的包中的阻塞操作封装成gevent可以识别的阻塞 # 没有这行代码time.sleep语句是不被gevent识别的 # 使用gevent一定要将这一行代码放到开头 import time import gevent def func1(): print("eat start") time.sleep(1)# 阻塞 print("eat end") def func2(): print("play start") time.sleep(1)# 阻塞 print("play end") g1 = gevent.spawn(func1)# 创建协程 g2 = gevent.spawn(func2) g1.join() # 等待协程g1结束 g2.join() # 等待协程g2结束 # gevent可以自动调度协程,实现在遇到IO操作时自动切换
协程爬虫
from gevent import monkey;monkey.patch_all()# 感知其他包中的阻塞 import requests import gevent def geturl(url): rep = requests.get(url) print(url,len(rep.text)) g1 = gevent.spawn(geturl,"https://www.baidu.com")# 创建协程 g2 = gevent.spawn(geturl,"https://www.iqiyi.com") g3 = gevent.spawn(geturl,"https://www.taobao.com") g4 = gevent.spawn(geturl,"https://www.sohu.com") gevent.joinall([g1,g2,g3,g4])# 将全部协程join与主程序同步,接收的是可迭代对象 # 同步的原因:异步执行同步接收结果,如果不同步则主程序直接执行完毕接收不到结果
协程实现socket并发
server
from gevent import monkey;monkey.patch_all() import socket import gevent def func(conn): conn.send(b"hello") print(conn.recv(1024).decode("utf8")) conn.close() sk = socket.socket() sk.bind(("127.0.0.1",8080)) sk.listen() g_list = [] while True: conn, addr = sk.accept() g = gevent.spawn(func,conn) g_list.append(g) sk.close()
client
import socket sk = socket.socket() sk.connect(("127.0.0.1",8080)) print(sk.recv(1024).decode("utf8")) msg = input(">>>").encode("utf8") sk.send(msg)