协程高并发 – asyncio异步

协程高并发 – asyncio异步aoao 快的协程

1 – 协程基础知识

2 – 执行协程函数中的代码

3 – 实现异步的正确方式

4 – 获取协程函数的返回值

5 – 协程的高并发实例

协程函数

 # 定义协程函数 async def func(): print("这是一个协程函数") 

协程对象

 # 定义协程函数 async def func(): print("这是一个协程函数") if __name__ == '__main__': # coro: 协程对象 # 此时 func函数 里面的代码 并不会像普通函数一样 被执行 coro = func() 

await关键字

 import asyncio """ await 只能在协程中使用 await + 可等待的对象 比如 await 协程对象/task对象/future对象 使用create_task方法 可以把协程对象 封装成task对象 官方建议使用task对象 """ async def job(): print("正在下载") await asyncio.sleep(1) # 协程中的睡眠 print("下载完成") async def run(): print("开始执行") await job() # 此处是 await 协程对象 await asyncio.create_task(job()) # 此处是 await task对象 await asyncio.ensure_future(job()) # 此处是 await future对象 print("执行完成") 

协程的顶层入口

 import asyncio # 定义协程函数 async def func(): print("这是一个协程函数") if __name__ == '__main__': # run方法: 协程的顶层入口 # 这样func函数中的代码就会执行 asyncio.run(func()) 

协程调用协程

import asyncio async def job(param): print("job执行了, 参数是", param) # 在协程中调用另一个协程 async def run(): # await 一个协程对象 就能执行这个协程 await job("python newbee") if __name__ == '__main__': asyncio.run(run()) 

运行结果

job执行了, 参数是 python newbee 

创建task对象

import asyncio async def job(param): print("job执行了, 参数是", param) # 在协程中调用另一个协程 async def run(): # 把协程对象 封装成 task对象 也能执行协程 asyncio.create_task(job("task对象")) if __name__ == '__main__': asyncio.run(run()) 

运行结果

job执行了, 参数是 task对象 

错误的调用写法

import asyncio import time async def job(a): print("正在下载 参数是", a, time.time()) print("下载完成 参数是", a, time.time()) print() await asyncio.sleep(1) # 使用了3次await async def run(): coro1 = job(1) await coro1 coro2 = job(2) await coro2 coro3 = job(3) await coro3 if __name__ == '__main__': t1 = time.time() asyncio.run(run()) print("耗时:", time.time() - t1) 

运行结果

很明显是同步效果,一个任务执行消耗1秒,三个就是3秒

正在下载 参数是 1 .2335 下载完成 参数是 1 .2335 正在下载 参数是 2 . 下载完成 参数是 2 . 正在下载 参数是 3 . 下载完成 参数是 3 . 耗时: 3.00457 

wait方法放在协程函数中

import asyncio import time async def job(a): print("正在下载 参数是", a, time.time()) print("下载完成 参数是", a, time.time()) print() await asyncio.sleep(1) # 用了1次await async def run(): coros = [job(a) for a in range(3)] await asyncio.wait(coros) if __name__ == '__main__': t1 = time.time() asyncio.run(run()) print("耗时:", time.time() - t1) 

运行结果

执行的时间戳一模一样,达到了真正的异步

正在下载 参数是 1 . 下载完成 参数是 1 . 正在下载 参数是 0 . 下载完成 参数是 0 . 正在下载 参数是 2 . 下载完成 参数是 2 . 耗时: 1.00017 

wait方法放在顶层入口

import asyncio import time async def job(a): print("正在下载 参数是", a, time.time()) print("下载完成 参数是", a, time.time()) print() await asyncio.sleep(1) if __name__ == '__main__': t1 = time.time() coros = [job(a) for a in range(3)] asyncio.run(asyncio.wait(coros)) print("耗时:", time.time() - t1) 

运行结果

执行的时间戳一模一样,达到了真正的异步

正在下载 参数是 1 . 下载完成 参数是 1 . 正在下载 参数是 2 . 下载完成 参数是 2 . 正在下载 参数是 0 . 下载完成 参数是 0 . 耗时: 1.00654 

使用回调函数

import asyncio from functools import partial # 回调函数 def callback(task): print("返回的结果是: ", task.result()) async def job(): print("job执行了") print("job结束了") return 100 async def run(): task = asyncio.create_task(job()) # 协程任务完成后, 回调函数才会执行  task.add_done_callback(partial(callback)) if __name__ == '__main__': asyncio.run(run()) 

运行结果

job执行了 job结束了 返回的结果是: 100 




最简单的接收

import asyncio async def job(param): print("job执行了, 参数是", param) return 100 async def run(): result1 = await job("coroutine") print(result1) result2 = await asyncio.create_task(job("task")) print(result2) if __name__ == '__main__': asyncio.run(run()) 

运行结果

job执行了, 参数是 coroutine 100 job执行了, 参数是 task 100 

使用wait方法

 import asyncio import time ''' wait方法会自动将协程对象 封装成task对象进行处理 wait方法在内部用set保存 它创建的task对象 因为set是无序的, 所以任务不是顺序执行 ''' now = lambda: time.time() async def func(idx): print(f"func执行了, 参数: { 
                                    idx}, 时间戳: { 
                                    now()}") await asyncio.sleep(1) return 100 async def run1(): tasks = [asyncio.create_task(func(idx)) for idx in range(10)] # 等待返回结果 await asyncio.wait(tasks) # 获取返回值 for task in tasks: print(task.result()) async def run2(): coros = [func(a) for a in range(10)] # wait方法会自动 把coros中的协程对象 封装成task对象 # wait方法返回一个元组, 元组中有两个集合 # done: 已经完成任务的task对象集合 # pending: 未完成任务的task对象集合 # 调用task对象的result方法可以获取 协程的返回结果 done, pending = await asyncio.wait(coros) for task in done: print(tasks.result()) if __name__ == '__main__': # 执行协程 asyncio.run(run1()) 

使用gather方法

 import asyncio import time ''' gather方法的任务是顺序执行的 ''' now = lambda: time.time() async def func(idx): print(f"func执行了, 参数: { 
                                       idx}, 时间戳: { 
                                       now()}") return 100 async def run1(): tasks = [asyncio.create_task(func(idx)) for idx in range(10)] # 等待返回结果 await asyncio.gather(*tasks) # 获取返回值 for task in tasks: print(task.result()) async def run2(): # 把多个协程对象装到一个列表中 coros = [func(a) for a in range(10)] # gather方法返回一个列表 # 列表中的每一个元素就是协程的返回结果 results = await asyncio.gather(*coros) for result in results: print(result) if __name__ == '__main__': # 执行协程 asyncio.run(run1()) 

使用as_completed方法

import asyncio from random import randint async def job(delay): print("开始下载", delay) await asyncio.sleep(delay) print("下载完成", delay) return delay async def use_as_completed(): tasks = [ asyncio.create_task(job(randint(1, 3))) for _ in range(6) ] # 使用as_completed方法的好处 # 任务先完成就立即返回, 而不是等待所有任务完成后再一起返回 for coro in asyncio.as_completed(tasks): result = await coro print("返回:", result) print("上面使用as_completed") async def use_wait(): tasks = [ asyncio.create_task(job(randint(1, 3))) for _ in range(6) ] # 使用wait方法 # 单个任务执行完了, 也要等待所有任务完成后, 再一起返回 done, pending = await asyncio.wait(tasks) for task in done: print("返回:", task.result()) print("上面使用wait") if __name__ == '__main__': asyncio.run(use_wait()) print() asyncio.run(use_as_completed()) 

运行结果

开始下载 1 开始下载 2 开始下载 1 开始下载 3 开始下载 3 开始下载 3 下载完成 1 下载完成 1 下载完成 2 下载完成 3 下载完成 3 下载完成 3 返回: 3 返回: 1 返回: 3 返回: 1 返回: 3 返回: 2 上面使用wait 开始下载 1 开始下载 3 开始下载 3 开始下载 2 开始下载 3 开始下载 1 下载完成 1 下载完成 1 返回: 1 返回: 1 下载完成 2 返回: 2 下载完成 3 下载完成 3 下载完成 3 返回: 3 返回: 3 返回: 3 上面使用as_completed 




执行5000个相同的协程

 import asyncio import time """ 一共有5000个 parse_detail 执行 """ # 返回时间戳, 方便记录 程序执行完毕 所消耗的时间 now = lambda: time.time() # 解析详情页 async def parse_detail(id): print(f"正在解析 详情页{ 
                                          id} --> { 
                                          now()}") await asyncio.sleep(1) # 睡眠1秒 print(f"详情页{ 
                                          id} 解析完成 --> { 
                                          now()}") # 解析列表页 async def parse_page(page): print(f"正在解析 列表页{ 
                                          page} --> { 
                                          now()}") # 内层的任务列表 # 每一个页面有1000个详情页 detail_coros = [ parse_detail(f"{ 
                                          page}/{ 
                                          id}") for id in range(1, 1001) ] await asyncio.wait(detail_coros) print(f"列表页{ 
                                          page} 解析完成 --> { 
                                          now()}") async def run(): # 外层的任务列表 # 构造了5个列表页 page_coros = [ parse_page(page) for page in range(1, 6) ] await asyncio.wait(page_coros) if __name__ == '__main__': t1 = now() asyncio.run(run()) print(f"耗时: { 
                                          now() - t1}") 







































版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/233649.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • kettle中实现动态SQL查询

    kettle中实现动态SQL查询详细说明kettle中两者方式实现动态查询,分别是占位符和变量方式,示例使用H2数据库,方便学习。

    2022年6月23日
    208
  • Dreamweaver8 网站制作软件使用教程

    Dreamweaver8 网站制作软件使用教程Dreamweaver是我喜欢做网站的软件。之所以喜欢Dreamweaver8是因为这个版本有折叠功能。下面说说它的使用方法。1、创建站点文件。注意看截图的顺序,如下图2、选择你喜欢的编辑模

    2022年7月4日
    22
  • 共享1款STC单片机的最小系统图「建议收藏」

    共享1款STC单片机的最小系统图「建议收藏」最新写的博客感觉越来越低端了……今天焊接、调试了一快板子。板子比较小,功能简单,使用了STC单片机,型号:STC15W408AS,封装:TSSOP20。焊板后的第一次下载程序。单片机5V供电,使用FT232RL模块,将FT232RL配置成IO口5V供电。按照以前的流程下载程序,STC-ISP软件一直无法检测单片机。解决思路:1、排除硬件故障。1.1单片机VDD供电正常5V。…

    2022年4月19日
    100
  • Android SDK Tools_android.intent.category.DEFAULT

    Android SDK Tools_android.intent.category.DEFAULTIamusingUbuntu11.10(x64),UsingandroidNDKIamtryingtobuildthestandalonetoolchainusingthefollowingcommandline:/%Somepath%/android-ndk-r7b/build/tools/make-standalone-toolchain.sh’…

    2025年6月14日
    3
  • java下载 文件_Java下载文件的几种方式「建议收藏」

    java下载 文件_Java下载文件的几种方式「建议收藏」1.以流的方式下载.publicHttpServletResponsedownload(Stringpath,HttpServletResponseresponse){try{//path是指欲下载的文件的路径。Filefile=newFile(path);//取得文件名。Stringfilename=file.getName();//取得文件的后缀名。Strin…

    2022年7月7日
    59
  • 小米网关一二三代的区别【转载】网关,mesh ,zigbee「建议收藏」

    小米网关一二三代的区别【转载】网关,mesh ,zigbee「建议收藏」小米智能家居北京小米科技有限责任公司索要资料  一般一个网关覆盖150平米的房子没什么问题,但是如果设备离网关太远,同时又隔了两三堵墙,中间又没有其它设备,那就会有点问题(zigbee设备每个设备之间是可以桥接信号的,它会自动选取信号最好的路径)。所以,一般一个房子一个网关就够了。如果是大房子,网关最好放房子中间位置,先买一个网关,如果信号不够,再买多一个。下面我们就来简单的介绍一下小米网关一二三代的区别!小米网关一二三代的区别  小米多功能网关一代二代和三代有什么区别?最直观的区别在于小米多功能

    2022年8月11日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号