Python中的协程

Python中的协程

定义一个协程

import asyncio
async def execute(x):
	print(x)
coroutine = execute(1)
print('coroutine:',coroutine)
loop = asyncio.get_event_loop()
loop.run_until_complete(coroutine)

运行结果

coroutine: <coroutine object execute at 0x10d675048>
1
  1. 第一行:导入asyncio这个包,才能使用asyncawait
  2. 第二行:使用async定义一个execute()方法。
  3. 第四行:直接调用该方法,但是方法没有执行,而是返回一个coroutine协程对象。
  4. 第五行:打印出来coroutine协程对象。
  5. 第六行:asyncio.get_event_loop创建一个事件循环loop
  6. 第七行:调用loop对象的run_until_complete()方法将协程注册到事件循环loop中,然后启动,才可以执行execute()方法打印输出结果。
  • async定义的方法会变成一个无法直接执行的coroutine对象,要将其注册到事件循环中才能执行。

定义第二个协程

第一种定义task对象方式

**task:**任务,是对协程对象(coroutine)的进一步封装,包含任务的各个状态,相比coroutine对象多了运行状态,如running、funished等。

import asyncio
async def execute(x):
	print(x)
	return x
coroutine = execute(1)
print('coroutine:',coroutine)
loop = asyncio.get_event_loop()
task = loop.create_task(coroutine)
print('Task:',task)
loop.run_until_complete(task)
print('Task:',task)

运行结果

coroutine: <coroutine object execute at 0x1048fa048>
Task: <Task pending coro=<execute() running at /Users/hubo/Downloads/untitled4.py:2>>
1
Task: <Task finished coro=<execute() done, defined at /Users/hubo/Downloads/untitled4.py:2> result=1>

我们将coroutine对象传递给run_until_complete方法时,实际上它进行了一个操作就是将coroutine封装成task对象。

  1. 第八行:调用loop对象的create_task()方法,将coroutine对象转化成task对象。
  2. 第九行:输出的时候发现taskpending状态。
  3. 第十行:我们将task对象添加到事件循环中执行。
  4. 第十一行:输出task对象的时候,发现状态变成了finished,同时result变成了1,也就是execute方法返回结果。

第二种定义task对象方式

import asyncio
async def execute(x):
	print(x)
	return x

coroutine = execute(2)
print('coroutine:',coroutine)
task = asyncio.ensure_future(coroutine)
loop = asyncio.get_event_loop()
print('Task:',task)
loop.run_until_complete(task)
print('Task:',task)

运行结果

coroutine: <coroutine object execute at 0x10dfdc048>
Task: <Task pending coro=<execute() running at /Users/hubo/Downloads/untitled4.py:2>>
2
Task: <Task finished coro=<execute() done, defined at /Users/hubo/Downloads/untitled4.py:2> result=2>

直接通过asyncioensure_future()方法,返回结果就是task对象,我们就不用借助于loop来定义。即使没有声明loop也可以定义task对象。

为Task绑定一个回调方法

import asyncio
import requests
async def request():
	url = 'http://baidu.com'
	status = requests.get(url)
	return status
def callback(task):
	print('Status:',task.result())
coroutine = request()
task = asyncio.ensure_future(coroutine)
task.add_done_callback(callback)
print('Task:',task)

loop = asyncio.get_event_loop()
loop.run_until_complete(task)
print('Task:',task)
  • 第11行:我们将callback()方法传递给了封装好的task对象,这样task执行完毕后,就可以调用callback()方法,同时task对象还会做为参数传递给callback()方法,调用task对象的result()方法获取返回结果。

多任务协程

上面的例子只执行了一次请求,当执行多次请求应该怎么办?定义一个task列表,然后使用asynciowait()方法就即可执行。

import asyncio
import requests
async def request():
	url = 'http://baidu.com'
	status = requests.get(url)
	return status
tasks = [asyncio.ensure_future(request()) for _ in range(5)]
print(tasks)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

for task in tasks:
	print('Task Result:',task.result())

运行结果

[<Task pending coro=<request() running at /Users/hubo/Downloads/untitled4.py:3>>, <Task pending coro=<request() running at /Users/hubo/Downloads/untitled4.py:3>>, <Task pending coro=<request() running at /Users/hubo/Downloads/untitled4.py:3>>, <Task pending coro=<request() running at /Users/hubo/Downloads/untitled4.py:3>>, <Task pending coro=<request() running at /Users/hubo/Downloads/untitled4.py:3>>]
Task Result: <Response [200]>
Task Result: <Response [200]>
Task Result: <Response [200]>
Task Result: <Response [200]>
Task Result: <Response [200]>
  1. 第7行:使用for循环创建五个task,组成一个列表。
  2. 第10行:把列表首先传递给了 asynciowait() 方法,然后再将其注册到时间循环中,就可以发起五个任务了。
  3. 第11行:将结果输出。

使用aiohttp

aiohttp 是一个支持异步请求的库,利用它和 asyncio 配合我们可以非常方便地实现异步请求操作。

import asyncio
import requests
import aiohttp
async def request():
	url = 'http://httpbin.org'
	session = aiohttp.ClientSession()
	response = await session.get(url)
	session.close()
	print(response)
tasks = [asyncio.ensure_future(request()) for _ in range(5)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

**注意:**将请求库由 requests 改成了 aiohttp,通过 aiohttp 的 ClientSession 类的 get() 方法进行请求。
await:遇到非阻塞的会继续执行,遇到阻塞的耗时请求会被挂起,会执行另一个task,当全部的task挂起后,就会继续等待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值