python并发编程-part3

  • 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()
    
  • 总结
    • 串行、并行、并发(图片-尚学堂)在这里插入图片描述
    • 进程是系统分配资源的最小单位,线程是程序执行的最小单位;线程上下文切换快得多;
      在这里插入图片描述
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值