- 比线程更小的执行单元;
- 用户自己控制;
- 某个函数,可以在任何地方保存当前函数的一些临时变量等信息,然后切换到另一个函数中;
- 协程自己主动让出CPU;
- 协程的切换只是单纯的操作CPU的上下文,比线程切换更迅速;
- 1:N模式,一个线程作为一个容器,里面放置多个协程;
- 使用IO密集型的程序。
Python中greenlet模块对协程进行了封装
比greenlet更强大并且可以自动切换任务模块gevent
在window环境下 ,在安装路径下的script目录下“SHIFT+鼠标右键” pip install gevent安装
linux环境下pip install gevent安装
greenlet,依旧需要手动切换协程
from greenlet import greenlet
import time
def fun1():
while True:
print("==fun1==")
gr2.switch()
time.sleep(1)
def fun2():
while True:
print("==fun2==")
gr1.switch()
time.sleep(1)
gr1 = greenlet(fun1)
gr2 = greenlet(fun2)
gr1.switch()
gevent自动切换协程
#coding=utf-8
import gevent
import time
def f(n):
for i in range(n):
print(gevent.getcurrent(), i)
gevent.sleep(1)#模拟耗时任务
g1 = gevent.spawn(f, 5)
g2 = gevent.spawn(f, 5)
g3 = gevent.spawn(f, 5)
g1.join()
g2.join()
g3.join()
gevent下载器
#coding=utf-8
from gevent import monkey
from urllib import request
import gevent
monkey.patch_all()
def download(url):
print("get:%s"%url)
reponse = request.urlopen(url)
data = reponse.read()
print("从%s收到%s数据"%(url, len(data)))
gevent.joinall([
gevent.spawn(download,"http://www.baidu.com"),
gevent.spawn(download,"http://www.sina.com"),
gevent.spawn(download,"http://www.sohu.com")
])
gevent版服务器
客户端
from socket import *
clientSocket = socket(AF_INET, SOCK_STREAM)
# 连接服务
serverAddr = ('127.0.0.1', 10004)
clientSocket.connect(serverAddr)
while True:
msg = input("请输入>>")
# 发送数据
clientSocket.send(msg.encode())
# 收数据
recvData = clientSocket.recv(1024)
print("<<%s"%recvData)
if msg == "bye":
break
clientSocket.close()
服务器
from gevent import monkey, socket
import gevent
#打补丁
monkey.patch_all()
#客户端处理
def handleRequest(conn):
while True:
#收数据
data = conn.recv(1024)
if not data:
conn.close()
print("++++")
break
else:
print("收到数据%s"%data)
conn.send(data)
#创建服务器
def server(port):
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('127.0.0.1', port))
s.listen(5)
while True:
cli, addr = s.accept()
gevent.spawn(handleRequest, cli)
if __name__ == "__main__":
server(10004)