什么是协程?
- 使用单线程 从程序的角度去实现并发执行
- 协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
目录
协程模块
0x01:greenlet模块
-
- 如果我们在单个线程内有
20
个任务,要想实现在多个任务之间切换,使用yield生成器的方式过于麻烦(需要先得到初始化一次的生成器,然后再调用send
。。。非常麻烦),而使用greenlet
模块可以非常简单地实现这20个任务直接的切换 - 由于
greenlet
模块不能实现自动检测IO操作,所以这里我们重点讲gevent
模块
- 如果我们在单个线程内有
0x02:gevent模块
-
异步执行任务,自动检测IO操作,自动切换
-
gevent
中用到的主要模式是Greenlet
, 它是以C扩展模块形式接入Python
的轻量级协程。Greenlet
全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
-
例 :结合
gevent
模块下的子模块monkey
,实现自动检测代码中的IO操作,并且自动切换gevent
定义的任务
from gevent import monkey;monkey.patch_all()
import gevent
import time
def eat(name):
print('%s eat 1' % name)
time.sleep(3)
print('%s eat 2' % name)
def play(name):
print('%s play 1' % name)
time.sleep(4)
print('%s play 2' % name)
start = time.time()
g1=gevent.spawn(eat, 'egon') # 将函数添加到gevent任务列表
g2=gevent.spawn(play, 'alex')
# g1.join()
# g2.join()
gevent.joinall([g1, g2]) # 代替单个join操作
stop = time.time()
print(stop-start)
start = time.time()
g1=gevent.spawn(eat, 'egon') # 将函数添加到gevent任务列表
g2=gevent.spawn(play, 'alex')
# g1.join()
# g2.join()
gevent.joinall([g1, g2]) # 代替单个join操作
stop = time.time()
print(stop-start)
运行结果
egon eat 1
alex play 1
egon eat 2
alex play 2
4.006288051605225
0x03:单线程下实现并发socket通讯
服务端代码
#基于gevent实现
from gevent import monkey,spawn;monkey.patch_all()
from socket import *
def communicate(conn):
while True:
try:
data=conn.recv(1024)
if not data:break
conn.send(data.upper())
except ConnectionResetError:
break
conn.close()
def server(ip,port):
server = socket(AF_INET, SOCK_STREAM)
server.bind((ip,port))
server.listen(5)
while True:
conn, addr = server.accept()
spawn(communicate,conn)
server.close()
if __name__ == '__main__':
g=spawn(server,'127.0.0.1',8090)
g.join()
客户端代码
from socket import *
from threading import Thread,currentThread
def client():
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8090))
while True:
client.send(('%s hello' %currentThread().getName()).encode('utf-8'))
data=client.recv(1024)
print(data.decode('utf-8'))
client.close()
if __name__ == '__main__':
for i in range(500):
t=Thread(target=client)
t.start()