Python - asyncio
入门
'''
1.event_loop: 时间循环,相当于一个无限循环,可以把一些函数注册到这个时间循环上,当满足发生条件
的时候,就调用相应的处理方法
2.coroutine: 协程对象类型,可以使用async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是会返回一个协程对象
我们可以将协程对象注册到事件循环中,它会被事件循环调用,
3.task: 任务,这是协程对象的进一步封装,包含协程对象的各个状态
'''
# 定义一个协成对象
async def execute(x):
print(f'Number:{x}')
coroutine = execute(1)
print(coroutine)
loop = asyncio.get_event_loop()
task = loop.create_task(coroutine)
print(task)
loop.run_until_complete(task)
print(task)
# out:
'''
<coroutine object execute at 0x000001C1361B3140>
<Task pending name='Task-1' coro=<execute() running at E:\PyProject\asyncioDemo\main.py:31>>
Number:1
<Task finished name='Task-1' coro=<execute() done, defined at E:\PyProject\asyncioDemo\main.py:31> result=None>
'''
# 也可以直接使用 :asyncio.ensure_future(coroutine) 创建task
async def execute(x):
print(f'Number:{x}')
coroutine = execute(1)
task = asyncio.ensure_future(coroutine)
loop = asyncio.get_event_loop()
print(task)
loop.run_until_complete(task)
print(task)
绑定回调函数
async def request():
url = 'http://www.baidu.com'
status = requests.get(url)
return status
def callback(task): # 回调函数
print(f'Status:{task.result()}')
coroutine = request()
task = asyncio.ensure_future(coroutine)
task.add_done_callback(callback) # 添加回调函数
print(task)
loop = asyncio.get_event_loop()
loop.run_until_complete(task) # 将协程对象注册到事件,并启动
print(task)
# 直接调用task.result() 也可以获得返回结果
async def request():
url = 'http://www.baidu.com'
status = requests.get(url)
return status # => task.result()
coroutine = request()
task = asyncio.ensure_future(coroutine)
print(task)
loop = asyncio.get_event_loop()
loop.run_until_complete(task) # 将协程对象注册到事件,并启动
print(task.result())
print(task)
多任务协程
多个任务怎么处理?可以创建一个task列表叫给asyncio.awit()
async def request():
url = 'http://www.baidu.com'
status = requests.get(url)
return status # => task.result()
tasks = [asyncio.ensure_future(request()) for _ in range(1, 5)]
print(tasks)
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
for task in tasks:
print(f'task result:{task.result()}')
# out:
'''
[<Task pending name='Task-1' coro=<request() running at E:\PyProject\asyncioDemo\main.py:88>>, <Task pending name='Task-2' coro=<request() running at E:\PyProject\asyncioDemo\main.py:88>>, <Task pending name='Task-3' coro=<request() running at E:\PyProject\asyncioDemo\main.py:88>>, <Task pending name='Task-4' coro=<request() running at E:\PyProject\asyncioDemo\main.py:88>>]
task result:<Response [200]>
task result:<Response [200]>
task result:<Response [200]>
task result:<Response [200]>
'''
# 但其实也依然是顺序执行,没有实现异步操作
await关键字
await关键字:它可以将耗时等待的操作挂起,让出控制权。如果协程在执行的时候遇到await,事件循环就会将本协程挂起,转而执行别的协程,直到其他协程挂起或执行完毕
await 后面的对象必须是如下格式之一:
- 一个原生协程对象
- 一个由types.coroutine 修饰的生成器,这个生成器返回协程对象
- 一个包含__await__方法的对象返回的一个迭代器
案例
import requests
import time
import logging
import asyncio
logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(levelname)s: %(message)s')
url = 'https://www.httpbin.org/delay/1' # 延迟1s
start_time = time.time()
for _ in range(1, 10):
resp = requests.get(url)
logging.info(f'scraping {url}')
end_time = time.time()
logging.info(f'total time {start_time - end_time} s')
#out 同步访问耗时 18s:
'''
2022-11-20 18:13:20,426 - INFO: scraping https://www.httpbin.org/delay/1
2022-11-20 18:13:22,395 - INFO: scraping https://www.httpbin.org/delay/1
2022-11-20 18:13:24,697 - INFO: scraping https://www.httpbin.org/delay/1
2022-11-20 18:13:26,675 - INFO: scraping https://www.httpbin.org/delay/1
2022-11-20 18:13:28,680 - INFO: scraping https://www.httpbin.org/delay/1
2022-11-20 18:13:30,728 - INFO: scraping https://www.httpbin.org/delay/1
2022-11-20 18:13:32,905 - INFO: scraping https://www.httpbin.org/delay/1
2022-11-20 18:13:34,886 - INFO: scraping https://www.httpbin.org/delay/1
2022-11-20 18:13:36,980 - INFO: scraping https://www.httpbin.org/delay/1
2022-11-20 18:13:36,980 - INFO: total time -18.95430302619934 s
'''
结合aiohttp 模块实现异步请求,优化上面程序:
import aiohttp
start = time.time()
async def get(url):
session = aiohttp.ClientSession()
resp = await session.get(url)
await resp.text()
await session.close()
return resp
async def request():
url = 'https://www.httpbin.org/delay/1'
resp = await get(url)
tasks = [asyncio.ensure_future(request()) for _ in range(10)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print(f'cost time:{end - start}')
# out 完成10个线程总计花费2s:
'''
Waiting for https://www.httpbin.org/delay/1...
Waiting for https://www.httpbin.org/delay/1...
Waiting for https://www.httpbin.org/delay/1...
Waiting for https://www.httpbin.org/delay/1...
Waiting for https://www.httpbin.org/delay/1...
Waiting for https://www.httpbin.org/delay/1...
Waiting for https://www.httpbin.org/delay/1...
Waiting for https://www.httpbin.org/delay/1...
Waiting for https://www.httpbin.org/delay/1...
Waiting for https://www.httpbin.org/delay/1...
ger response<ClientResponse(https://www.httpbin.org/delay/1) [200 OK]>
<CIMultiDictProxy('Date': 'Sun, 20 Nov 2022 10:22:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '370', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
ger response<ClientResponse(https://www.httpbin.org/delay/1) [200 OK]>
<CIMultiDictProxy('Date': 'Sun, 20 Nov 2022 10:22:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '370', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
ger response<ClientResponse(https://www.httpbin.org/delay/1) [200 OK]>
<CIMultiDictProxy('Date': 'Sun, 20 Nov 2022 10:22:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '370', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
ger response<ClientResponse(https://www.httpbin.org/delay/1) [200 OK]>
<CIMultiDictProxy('Date': 'Sun, 20 Nov 2022 10:22:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '370', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
ger response<ClientResponse(https://www.httpbin.org/delay/1) [200 OK]>
<CIMultiDictProxy('Date': 'Sun, 20 Nov 2022 10:22:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '370', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
ger response<ClientResponse(https://www.httpbin.org/delay/1) [200 OK]>
<CIMultiDictProxy('Date': 'Sun, 20 Nov 2022 10:22:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '370', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
ger response<ClientResponse(https://www.httpbin.org/delay/1) [200 OK]>
<CIMultiDictProxy('Date': 'Sun, 20 Nov 2022 10:22:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '370', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
ger response<ClientResponse(https://www.httpbin.org/delay/1) [200 OK]>
<CIMultiDictProxy('Date': 'Sun, 20 Nov 2022 10:22:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '370', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
ger response<ClientResponse(https://www.httpbin.org/delay/1) [200 OK]>
<CIMultiDictProxy('Date': 'Sun, 20 Nov 2022 10:22:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '370', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
ger response<ClientResponse(https://www.httpbin.org/delay/1) [200 OK]>
<CIMultiDictProxy('Date': 'Sun, 20 Nov 2022 10:22:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '370', 'Connection': 'keep-alive', 'Server': 'gunicorn/19.9.0', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Credentials': 'true')>
cost time:2.4535582065582275
Process finished with exit code 0
'''
另一种实现协程的方式,python 3.8 已经弃用:
import aiohttp
start = time.time()
# py 3.8 已经弃用
@asyncio.coroutine # 等价于 async def get(url)
def get(url):
session = aiohttp.ClientSession()
resp = yield from session.get(url) # 等价于 await session.get(url)
yield from resp.text()
yield from session.close()
return resp
@asyncio.coroutine
def request():
url = 'https://www.httpbin.org/delay/1'
print(f'Waiting for {url}...')
resp = yield from get(url)
print(f'ger response{resp}')
tasks = [asyncio.ensure_future(request()) for _ in range(10)]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end = time.time()
print(f'cost time:{end - start}')
本文来自博客园,作者:chuangzhou,转载请注明原文链接:https://www.cnblogs.com/czzz/p/16908534.html