协程基础
底层实现
- 协程的底层是使用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)