【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)

 

posted @ 2022-09-09 16:33  PythonNew_Mr.Wang  Views(192)  Comments(0)    收藏  举报