【Python小随笔】asyncio异步 简单易懂的 理解与使用
1:基础理解异步如何实现的
# 请记住async创建的对象一定是coroutine对象
async def func(name):
res = random.randint(1,10)
print("{}需要{}秒".format(name,res))
# await 后面一定是coroutine对象: 等待中的任务,TASK对象,Tutrure对象
await asyncio.sleep(res)
print("NAME IS",name)
async def main():
print("main")
await asyncio.gather(func("小明"),func("小红"),func("小黄"))
s = time.time()
asyncio.run(main())
print("耗时", time.time() - s)
# 输出:
main
小明需要4秒
小红需要1秒
小黄需要9秒
NAME IS 小红
NAME IS 小明
NAME IS 小黄
耗时 9.000617980957031 # 这里说明异步IO确实缩短了时间,如果是同步应该要耗时9+1+4
2:异步与同步的时间对比
# 使用同步请求数据 # 普通请求函数 def requests_get_baidu(session): session.get(url="https://www.baidu.com/") def requests_get_zhihu(session): session.get(url="https://www.zhihu.com/") def requests_get_bilibili(session): session.get(url="https://www.bilibili.com/") # 执行普通请求主函数 def main(): session = requests.Session() # 每个循环5次请求 for _ in range(5): requests_get_baidu(session) requests_get_zhihu(session) requests_get_bilibili(session) # 执行 if __name__ == '__main__': s = time.time() main() print("耗时", time.time() - s)
# 输出: 耗时 4.930192232131958
# 使用异步等待方式请求数据
# =============创建coroutine对象============
async def requests_get_baidu(session):
time.sleep(2)
session.get(url="https://www.baidu.com/")
async def requests_get_zhihu(session):
session.get(url="https://www.zhihu.com/")
async def requests_get_bilibili(session):
session.get(url="https://www.bilibili.com/")
# =============创建coroutine对象============
# =============创建异步事件============
async def async_get_baidu(session):
await requests_get_baidu(session) # 异步等待IO 执行 coroutine对象
async def async_get_zhihu(session):
await requests_get_zhihu(session) # 异步等待IO 执行 coroutine对象
async def async_get_bilibili(session):
await requests_get_bilibili(session) # 异步等待IO 执行 coroutine对象
# =============创建异步事件============
async def main():
session = requests.Session()
task_list = []
# 添加异步事件
for _ in range(5):
task_list.append(async_get_baidu(session))
task_list.append(async_get_zhihu(session))
task_list.append(async_get_bilibili(session))
await asyncio.gather(*task_list) # 添加事件循环/
s = time.time()
asyncio.run(main())
print("耗时", time.time() - s)
# 输出: 耗时 5.553693532943726
问题: 按照理解,挂起这里的coroutine对象,等待被循环事件启动就可以进行异步操作,但是得出的结果与同步并没有明显的缩短事件,反而因为不稳定性还增加了?
3:正确的使用方式: 在异步爬虫中,结合aiohttp 一起使用
import asyncio
import aiohttp
# =============创建异步事件============
async def async_get_baidu():
aiohttp_session = aiohttp.ClientSession() # 创建aiohttp异步请求
respones = await aiohttp_session.get(url="https://www.baidu.com/") # 异步非阻塞请求等待时间
await respones.text() # 异步 请求到数据
await aiohttp_session.close() # 最新版本提示警告:一定要关闭这个异步请求
""" 获取到数据后可以 进行自定义逻辑函数 """
async def async_get_zhihu():
aiohttp_session = aiohttp.ClientSession()
respones = await aiohttp_session.get(url="https://www.zhihu.com/")
await respones.text()
await aiohttp_session.close()
# 获取到数据后可以 进行自定义逻辑函数
async def async_get_bilibili():
aiohttp_session = aiohttp.ClientSession()
respones = await aiohttp_session.get(url="https://www.bilibili.com/")
await respones.text()
await aiohttp_session.close()
# 获取到数据后可以 进行自定义逻辑函数
# =============创建异步事件============
async def main():
task_list = []
# 添加异步事件
for _ in range(5):
task_list.append(async_get_baidu())
task_list.append(async_get_zhihu())
task_list.append(async_get_bilibili())
await asyncio.gather(*task_list) # 添加事件循环
# 执行
if __name__ == '__main__':
s = time.time()
asyncio.get_event_loop().run_until_complete(main())
print("耗时", time.time() - s)
# 输出:
循环5次: 耗时 1.4885777235031127
循环100次: 耗时 3.825554609298706
import asyncio
import aiohttp
# 第二种方式(推荐)
# coroutine对象创建
async def request_data(mark_urls,sessions,semaphore):
"""
:param mark_urls: 目标网址
:param sessions: session
:param semaphore: 最大并发数
:PS 输出文本的使用一定要使用以下方式
"""
async with semaphore:
async with aiohttp.ClientSession(cookies=sessions.cookies) as aiohttp_session:
async with aiohttp_session.get(url=mark_urls) as resp:
res = await resp.text()
# 以下是对数据的操作
print("数据{}-------时间{}".format(res[0:20],change_time(int(time.time()))[1]))
# 主函数异步创建
async def main(mark_urls,session):
"""
:param mark_urls: 目标网址
:param session: session
:return: 返回coroutine对象的返回值
"""
semaphore = asyncio.Semaphore(500) # 限制并发量为500
task_list = []
for i in range(500):
task_list.append(request_data(mark_urls,session,semaphore))
res = await asyncio.gather(*task_list) # 添加事件循环
return res
if __name__ == '__main__':
s = time.time()
session = session_requests_login("username", "password") # 登录函数 返回session
SSS = asyncio.get_event_loop().run_until_complete(main("你要登录后操作的地址",session)) # 登录后的异步操作
print("耗时", time.time() - s)
Python全栈(后端、数据分析、脚本、爬虫、EXE客户端) / 前端(WEB,移动,H5) / Linux / SpringBoot / 机器学习

浙公网安备 33010602011771号