python并发编程

更新时间:2020-12-15 10:46:18 点击次数:969次
Greenlet & Gevent的使用
前文(Python并发编程-part2)提到使用yield的生成器形成任务切换;缺点是如果单线程有20个任务,则yield方式很麻烦(需要初始化生成器,然后send内容进入生成器)
真正的协程模块使用greenlet完成的多任务切换,很轻松
Gevent 封装了Greenlet,可以不用一定程度减少手动切换的麻烦;
对于以下Gevent例子,如果串行实现,大概要4s,Gevent的自动切换使得实际时间只要2s左右;
from greenlet import greenlet
def gf(name):
print(f"{name}: 吃东西")
g2.switch("小张")  # 切换到g2任务并且对name初始化,然后suspend等待再次激活
print(f"{name}: 看电影")
g2.switch()
def bf(name):
print(f"{name}: ok")
g1.switch()  # name初始化过了,不用再传入
print(f"{name}: 下午")

if __name__=="__main__":
g1 = greenlet(gf)
g2 = greenlet(bf)
# 切换
g1.switch("小陈")  # 切换到g1任务并且对name初始化
==============================
# Gevent改进
import gevent
def gf(name):
print(f"{name}: 吃东西")
# g2.switch("小张")  # 切换到g2任务并且对name初始化,然后suspend等待再次激活
gevent.sleep(2)  # 注意不是time的sleep,是Gevent自己的sleep(伪IO),才可以自动切换;使用time sleep需要在最前面加上补丁 monkey.patch_all(),monkey来自from genvent import monkey
print(f"{name}: 看电影")
# g2.switch()
def bf(name):
print(f"{name}: ok")
# g1.switch()  # name初始化过了,不用再传入
gevent.sleep(2)
print(f"{name}: 下午")

if __name__=="__main__":
# g1 = greenlet(gf)
# g2 = greenlet(bf)
g1 = gevent(gf, "小陈")  # 更简洁
g2 = gevent(bf, "小张")
# 切换
# g1.switch("小陈")  # 切换到g1任务并且对name初始化
# 启动任务
g1.join()
g2.join()  # 或者这两步可以合并为 gevent.joinall([g1,g2])

async IO 异步IO:python3.4引入,利用事件循环机制处理多并发

import asyncio
# 创建协程-旧的方法,通过装饰器
@asyncio.coroutine  # before python3.5
def func1():
for i in range(5):
print(f"吃瓜-{i}")
yield from asyncio.sleep(1)  

# 创建协程-新的方法,通过关键字
async def func2():  # >= python3.5
for i in range(5):
print(f"不吃-{i}")
await asyncio.sleep(2)  # callback的使用可能是事件加入和IO结束时触发通知

if __name__ == "__main__":
g1 = func1()
g2 = func2()
# 创建事件循环
loop = asyncio.get_event_loop()
# 监听事件循环
loop.run_until_complete(asyncio.gather(g1,g2))
# 关闭事件循环
loop.close()
===============================
# 测试回调函数callback
import asyncio
import functools
async def compute(x, y):
print("compute x + y ...")
await asyncio.sleep(1)  # 交出cpu控制权
return x+y
async def print_result(x, y):
# 创建任务以便添加callback
task = asyncio.create_task(compute(x,y))
# 添加回调函数
task.add_done_callbback(functools.partial(end, x, y))
for i in range(1000000):
if i % 5000 == 0:
print(i)
asyncio.sleep(0.2)  # 要交出cpu控制权,以便回调函数能执行
# 回调函数
def end(x, y, t):  # t即task对象
print(f"{x} + {y} = {t.result}")

if __name__=="__main__":
# 创建事件循环
loop = asyncio.get_event_loop()
# 添加事件、任务
loop.run_until_complete(print_result(2, 3))
# 关闭事件循环
loop.close()

本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是一个个人学习交流的平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽,造成漏登,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

回到顶部
嘿,我来帮您!