python进程、线程和协程(四)

python多协程

多协程运行原理

单线程的执行路径
在这里插入图片描述

多协程的执行路径
在这里插入图片描述
协程的运行核心原理是
1、程序在线程里创建一个超级循环(while True)
2、将每一个任务放到任务列表中
3、运行这个超级循环,当遇到CPU操作时,CPU执行;当遇到IO操作时,此时CPU切换到下一个任务的CPU操作,此时IO等待过程中CPU继续运行,不会造成资源浪费
4、一直运行这个循环,直至所有任务执行完毕。

协程的发展

python2.x对协程的支持比较有限

  • 生成器yield实现了一部分但不完全;
  • greenlet库可以实现协程但是需要手动切换;
  • gevent模块倒是有比较好的实现;

python3.4加入了asyncio模块;
python3.5又提供了async/await语法层面的支持;
Python3.6中asyncio模块更加完善和稳定。

python多协程(异步IO)

注:本文代码使用python版本为python3.7+

首先介绍几个概念:

  • 1、event_loop 事件循环:超级循环,可以把一些函数注册到这个事件循环上,当满足条件时,就会调用对应的处理方法。
  • 2、coroutine 协程:协程对象,只一个使用async关键字定义的函数,他的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环中,由事件循环调用。
  • 3、task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程的进一步封装,其中包含任务的各种状态。
  • 4、future:代表将来执行或没有执行的任务结果。它与task没有本质的区别。
  • 5、async/await 关键字:python3.5用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。
import asyncio
# 获取时间循环
loop = asyncio.get_event_loop()

# 定义协程函数
async def myfunc(url):
	await get_url(url)

# 创建task列表
tasks = [loop.create_task(myfunc(url)) for url in urls]

def callback(future):
	print future.result()
for task in tasks:
	task.add_done_callback(callback)
	
"""
绑定回调:在task执行完毕的时候可以获取执行的结果,回调的最后一个参数是future对象,通过这个对象可以获取协程的返回值,如果回调函数需要多个参数,可以通过偏函数导入,即task.add_done_callback(functools.partial(call_back_2, 100))
"""

# 执行事件列表
loop.run_until_complete(asyncio.wait(tasks))

"""
run_until_complete根据传递的参数的不同,返回的结果也有所不同

1、run_until_complete()传递的是一个协程对象或task对象,则返回他们finished的返回结果(前提是他们得有return的结果,否则返回None)
2、run_until_complete(asyncio.wait(多个协程对象或任务)),函数会返回一个元组包括(done, pending),通过访问done里的task对象,获取返回值
3、run_until_complete(asyncio.gather(多个协程对象或任务)),函数会返回一个列表,列表里面包括各个任务的返回结果,按顺序排列
"""

案例:

import asyncio
import aiohttp
import time

# 协程函数
async def async_crawl(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            result = await resp.text()
            print(f"craw url: {url}, {len(result)}")
            return result

# 回调函数
def callback(future):
	print(future.result())

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    tasks = [
	    loop.create_task(async_crawl(url))
	    for url in ["http://www.baidu.com", "http://www.baidu.com"]
	]

	for task in tasks:
		task.add_done_callback(callback)
		
    start =time.time()
    loop.run_until_complete(asyncio.wait(tasks))
    end = time.time()
    print(end - start)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值