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