python3异步编程介绍


一、概述:

 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

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM