一、概述:
1.异步编程是一种并发编程的模式,其关注点是通过调度不同任务之间的执行和等待时间,通过减少处理器的闲置时间来达到减少整个程序的执行时间;
2.异步编程跟同步编程模型最大的不同就是其任务的切换,当遇到一个需要等待长时间执行的任务的时候,我们可以切换到其他的任务执行;
3.与多线程和多进程编程模型相比,异步编程只是在同一个线程之内的的任务调度,无法充分利用多核CPU的优势,所以特别适合IO阻塞性任务;
4.同步是指完成事务的逻辑,先执行第一个事务,如果阻塞了,会一直等待,直到这个事务完成,再执行第二个事务,顺序执行异步是和同步相对的,异步是指在处理调用这个事务的之后,不会等待这个事务的处理结果,直接处理第二个事务去了,通过状态、通知、回调来通知调用者处理结果。多线程和多进程都是通过异步的方式处理事物。
二、异步与同步理解图
同步:
异步:
理解:从上图可以看出同步在长时间处理时,程序一直等待中,,异步在长时间处理时,可以切换到别的任务(做别的事情)
三、 同步VS异步:
#!/usr/bin/env python # -*- coding: utf-8 -*- ###__________________________________________同步实现网站访问________________________________________ import time def visit_url(url, response_time): """ 访问url """ print("visit: {} - {}".format(int(time.time()),url)) time.sleep(response_time)#同步等待 print("response: {}".format(int(time.time()))) return "访问{}, 已得到返回结果".format(url) def run_task(): visit_url('http://itest.info', 2) visit_url('http://www.testpub.cn', 3) if __name__ == "__main__": start_time = time.perf_counter()#获取开始时间 run_task() print("消耗时间:{}秒".format(time.perf_counter() - start_time)) ###___________________________________________异步实现网站访问________________________________________________ import asyncio import time async def visit_url(url, response_time): """访问 url""" print("visit: {} - {}".format(int(time.time()),url)) await asyncio.sleep(response_time) print("response: {}".format(int(time.time()))) # async def run_task(): # '''非并发写法''' # await visit_url('http://itest.info', 2) # await visit_url('http://www.testpub.cn', 3) # # if __name__ == "__main__": # start_time = time.perf_counter() # asyncio.get_event_loop().run_until_complete(run_task()) # print("消耗时间:{}秒".format(time.perf_counter() - start_time)) ''' 运行结果(消耗时间没有变化): visit: 1649735857 - http://itest.info response: 1649735859 visit: 1649735859 - http://www.testpub.cn response: 1649735862 消耗时间:5.001019820249864秒 备注: 你会发现,两次运行并无差别。 如果想达到并发的效果,可以通过gather()创建任务。修改run_task() 函数 ''' async def run_task(): '''并发函数的写法''' url1 = visit_url('http://wangzhen.com', 2) url2 = visit_url('http://www.testpub.cn', 3) await asyncio.gather(url1, url2) #asyncio.gather() 方法将多个异步任务(两个 url)包装成一个新的异步任务。 if __name__ == "__main__": start_time = time.perf_counter()#获取开始时间 asyncio.get_event_loop().run_until_complete(run_task()) print("消耗时间:{}秒".format(time.perf_counter() - start_time))
###################简单的异步函数调用################### import asyncio async def my_async_function(delay): print("Start task {}".format(delay)) #只阻塞当前函数,这里实际是处理的任务(如IO读写操作) await asyncio.sleep(delay)#非必填 print("End task {}".format(delay)) async def main(): tasks = [my_async_function(1), my_async_function(2), my_async_function(3)] await asyncio.wait(tasks) print("所有任务执行完成!") asyncio.run(main())
四、案例代码:
案例1-async异步函数调用
#!/usr/bin/env python # -*- coding: utf-8 -*- ''' 在函数前加上 async那么这个函数就是异步函数 ''' import asyncio import time async def chen(a, b): await asyncio.sleep(4) #异步等待时间(在这个时间内cpu可以执行其他函数),所以可以缩短程序运行时间 #time.sleep(4)#同步等待时间(程序堵塞不执行,等时间到了才执行) print('111111111111111111111111111111') async def hello1(a, b): print('in 11111',int(time.time()))#获取当前时间戳 time.sleep(2) #模拟同步请求 print("hello1111消耗前",int(time.time())) await asyncio.sleep(3) # 模拟耗时任务3秒 print("hello1111消耗后",int(time.time())) return a + b async def hello2(a, b): print('in 22222',int(time.time())) time.sleep(2) #模拟同步请求 print("hello2222消耗前",int(time.time())) await asyncio.sleep(6) # 模拟耗时任务2秒 print("hello2222消耗后",int(time.time())) return a - b async def hello3(a, b): print('in 3333',int(time.time())) time.sleep(2) #模拟同步请求 print("hello33333消耗前",int(time.time())) #await asyncio.sleep(4) # 模拟耗时任务4秒(这里是异步耗时等待) await chen(a, b)#调用函数 print("hello33333消耗后",int(time.time())) return a * b async def main(): results = await asyncio.gather(hello1(10, 5), hello2(10, 5), hello3(10, 5))#多任务执行,返回的是结果列表 for result in results: print('执行结果',result) start=int(time.time())#获取当前时间戳 asyncio.get_event_loop().run_until_complete(main())#一体化执行 (asyncio.get_event_loop()获取消息循环体,,run_until_complete(main())将协程函数添加到事件循环,并启动main() ) end=int(time.time())#获取当前时间戳 print('程序总耗时:{}秒'.format(end-start))
案例2-协程异步函数:
#!/usr/bin/python3 # -*- coding: utf-8 -*- #_____________________________async/await 是python3的新特性,可以进行协程运行。个人将他理解成多线程。实现代码如下__________________________________________________ import time import asyncio async def SleepTime(ts): print('tasks列表为',ts) if ts == 3: await asyncio.sleep(10) #当ts等于3的时候,让挂起的时间为10s,其他的按正常挂起,验证协程时间。 else: await asyncio.sleep(ts) async def main(loop): tasks = [] #这里就有6个函数 for i in range(6): print("第{}次".format(i)) tasks.append(loop.create_task(SleepTime(i))) #相当于开启了一个线程 print("结束{}".format(i)) print("*********************") await asyncio.wait(tasks) #等待所有的任务完成。 if __name__ == "__main__": # main() print("程序开始") tb = time.time() print(tb) #记录当前时间 loop = asyncio.get_event_loop()#获取消息循环体,,创建一个事件loop loop.run_until_complete(main(loop))#将协程函数添加到事件循环,并启动 loop.close()#关闭事件 print(time.time()-tb) #记录结束时间 print("程序end")
案例3-异步请求-同个接口请求多次:
import httpx import asyncio import time async def request(client): resp = await client.get('http://httpbin.org/get') result = resp.json() async def main(): async with httpx.AsyncClient() as client: # 100 次调用 task_list = [] for _ in range(100): req = request(client) task = asyncio.create_task(req) task_list.append(task) await asyncio.gather(*task_list) if __name__ == "__main__": #开始 start = time.time() asyncio.run(main()) # 结束 end = time.time() print('异步:发送100次请求,耗时:{}'.format(end - start))
案例4-异步请求-请求不同的接口:
#!/usr/bin/env python # -*- coding: utf-8 -*- import asyncio import aiohttp import time,io,sys ###________________________________________异步调用不同接口____________________________________________________ async def fetch(session, url): print("发送请求", url) async with session.get(url, verify_ssl=False) as response: content = await response.content.read() if '.jpg' in url: with open(file=str(time.time()) + ".jpg", mode="wb") as file_object: file_object.write(content) else: print(content) #print('33333333333333333333333333333333333333333333333333333333333333333333') with open(file=str(time.time()) + ".txt", mode="w") as file_object: file_object.write(str(content)) print("保存成功", url) async def main(): async with aiohttp.ClientSession() as session: url_list = [ "https://www.baidu.com", "https://scpic.chinaz.net/files/pic/pic9/202107/apic34061.jpg", "https://www.jd.com" ] tasks= [asyncio.ensure_future(fetch(session,i)) for i in url_list]#组装任务列表 await asyncio.wait(tasks)#异步启动任务 if __name__ == '__main__': asyncio.get_event_loop().run_until_complete(main())#创建时间循环并启动 ###___________________________________________异步调用不同接口_________________________________________________ sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030') #改变标准输出的默认编码 async def get(url): session = aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=64, ssl=False)) response = await session.get(url) res_text=await response.text() print('接口响应内容:',res_text) ###把响应结果写入文件 with open(file=str(time.time()) + ".txt", mode="w",encoding="UTF-8") as file_object: file_object.write(res_text) await session.close() return response async def request(url): print('当前url:',url) await get(url)#异步调用函数 if __name__ == "__main__": start = time.time()#开始时间戳 bb=['http://www.baidu.com','http://www.taobao.com','http://www.jd.com']#需要执行的url tasks = [asyncio.ensure_future(request(a)) for a in bb]#创建任务列表 loop = asyncio.get_event_loop()#获取消息循环体,,创建一个事件loop loop.run_until_complete(asyncio.wait(tasks))#将协程函数添加到事件循环,并启动 end = time.time()#结束时间戳 print( '程序总耗时:',end - start)
相关连接:
https://www.cnblogs.com/yarightok/p/15997908.html ..................................异步函数关键字
https://blog.csdn.net/weixin_49346599/article/details/108608812.................python异步接口测试(案例)
https://blog.csdn.net/qq_37674086/article/details/122595748 ....................协程异步场景简单使用示例
https://blog.csdn.net/weixin_54556126/article/details/122366882 ................python自动化测试中使用异步
https://blog.csdn.net/qq_43380180/article/details/111573642.......................异步 async/await
https://www.cjavapy.com/article/2428/ ..........................................................Python 异步编程 协程(async/await)
https://www.cnblogs.com/bubbleboom/p/14971052.html...............................Python协程和异步IO