大家在使用python做playwright自動(dòng)化測(cè)試的過(guò)程中,一定會(huì)發(fā)現(xiàn)下面這種異步用法
async def func():
? ? ? await api
? ? ? await api
很多同學(xué)可能只是按照這種寫(xiě)法來(lái)編寫(xiě)項(xiàng)目的自動(dòng)化測(cè)試代碼,對(duì)于具體細(xì)節(jié)可能并不了解,今天我就來(lái)講一下playwright異步用法的相關(guān)技術(shù)細(xì)節(jié)。建議大家拷貝文檔中的腳本實(shí)際運(yùn)行一下,學(xué)習(xí)的效果會(huì)更好!
同步和異步的概念
同步:發(fā)送一個(gè)請(qǐng)求,等待返回,然后再發(fā)送下一個(gè)請(qǐng)求
異步:發(fā)送一個(gè)請(qǐng)求,不等待返回,隨時(shí)可以再發(fā)送下一個(gè)請(qǐng)求
async 與 await
python在3.5以后引入async和await來(lái)強(qiáng)化自身的異步編程,提升效率。async 是異步的簡(jiǎn)寫(xiě),而 await 可以認(rèn)為是 async wait 的簡(jiǎn)寫(xiě)。async 用于申明一個(gè) function 是異步的,而 await 用于等待一個(gè)異步方法執(zhí)行完成。異步函數(shù)的特點(diǎn)是能在函數(shù)執(zhí)行過(guò)程中掛起,去執(zhí)行其他異步函數(shù),等到掛起條件結(jié)束后再回來(lái)繼續(xù)執(zhí)行。await的作用是掛起函數(shù),等待函數(shù)操作完成,這時(shí)候回去執(zhí)行其他的異步函數(shù),而不是傻等,等掛起的執(zhí)行完成以后將會(huì)從其他異步函數(shù)處返回,執(zhí)行掛起結(jié)束的函數(shù)。await只可以對(duì)異步函數(shù)使用,普通函數(shù)使用會(huì)報(bào)錯(cuò)。await的本質(zhì)是通過(guò)yield from 實(shí)現(xiàn)的,關(guān)于yield生成器相關(guān)知識(shí)點(diǎn)這里就不詳細(xì)介紹了。
例如:兩個(gè)異步程序async a、async b:
a中一步有await,當(dāng)程序碰到關(guān)鍵字await后,異步程序a掛起,去執(zhí)行異步b程序(就相當(dāng)于從一個(gè)函數(shù)內(nèi)部跳出去執(zhí)行其他函數(shù));當(dāng)掛起條件結(jié)束時(shí)候,不管b是否執(zhí)行完,要馬上從b程序中跳出來(lái),回到原程序a執(zhí)行原來(lái)的操作;如果await后面跟的b函數(shù)不是異步函數(shù),那么操作就只能等b執(zhí)行完再返回,無(wú)法在b執(zhí)行的過(guò)程中返回,這樣就相當(dāng)于直接調(diào)用b函數(shù),沒(méi)必要使用await關(guān)鍵字了。因此,需要await后面跟的是異步函數(shù)。
舉個(gè)例子
import time
import asyncio
async def wait1():
print('wait1 start')
await asyncio.sleep(1)
print('wait1 end')
async def wait3():
print('wait3 start')
await asyncio.sleep(3)
print('wait3 end')
async def wait5():
print('wait5 start')
await asyncio.sleep(5)
print('wait5 end')
# 2. 將異步函數(shù)加入事件隊(duì)列
tasks = [
wait1(),
wait3(),
wait5(),
]
if __name__ == '__main__':
# 創(chuàng)建一個(gè)事件循環(huán)
loop = asyncio.get_event_loop()
startTime = time.time()
# 執(zhí)行隊(duì)列實(shí)踐,直到最晚的一個(gè)事件被處理完畢后結(jié)束
loop.run_until_complete(asyncio.wait(tasks))
# 如果不在使用loop,建議使用關(guān)閉,類似操作文件的close()函數(shù)
loop.close()
endTime = time.time()
print("sum time: ",endTime-startTime)
運(yùn)行結(jié)果
wait5 start
wait3 start
wait1 start
wait1 end
wait3 end
wait5 end
sum time: 5.000609874725342
上面這段代碼大家可以多執(zhí)行幾次,我們會(huì)發(fā)現(xiàn):不管wait1 wait3,wait5 哪個(gè)函數(shù)先執(zhí)行,但是最后end的順序一定是 wait1>wait3>wait5。一共運(yùn)行的時(shí)間 在5s左右,充分地證明了三個(gè)函數(shù)是并行執(zhí)行的!
接下來(lái),我們可以對(duì)代碼進(jìn)行如下修改:
async def wait3():
print('wait3 start')
time.sleep(3)
print('wait3 end')
然后再次運(yùn)行代碼,結(jié)果如下:
wait5 start
wait3 start
wait3 end
wait1 start
wait1 end
wait5 end
sum time: 5.002418518066406
大家會(huì)發(fā)現(xiàn),只有wait3 end 發(fā)生后,才會(huì)出現(xiàn)wait1 end 和wait5 end(),很好的證明了上面的話:如果await后面跟的b函數(shù)不是異步函數(shù),那么操作就只能等b執(zhí)行完再返回,無(wú)法在b執(zhí)行的過(guò)程中返回,這樣就相當(dāng)于直接調(diào)用b函數(shù),沒(méi)必要使用await關(guān)鍵字了。我們可以任意調(diào)整task的執(zhí)行順序,例如:
tasks = [
wait1(),
wait5(),
wait3(),
]
執(zhí)行最慢的情況就是,wait3 第一個(gè)start,等待wait3 end后,才能執(zhí)行wait1 或者wait5
wait3 start
wait3 end
wait5 start
wait1 start
wait1 end
wait5 end
sum time: 8.000799894332886
一個(gè)易犯的錯(cuò)誤
當(dāng)我們?cè)谕椒椒ㄖ屑尤隺wait,執(zhí)行代碼的時(shí)候會(huì)報(bào)錯(cuò),也就是說(shuō)像下面這樣編寫(xiě)playwright腳步是不對(duì)的,因?yàn)閟ync_playwright() 是同步方法!
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(channel="chrome")
page = browser.new_page()
await page.goto("http://www.baidu.com")
print(page.title())
browser.close()
Playwright使用異步方法的正確姿勢(shì)
如下代碼會(huì)正常運(yùn)行,通過(guò)await可以保證腳本的運(yùn)行順序
async def playwright_async_demo():
async with async_playwright() as p:
browser = await p.chromium.launch(channel="chrome")
page = await browser.new_page()
await page.goto("http://www.baidu.com")
asyncio.run(playwright_async_demo())
如果我們把上面代碼中 browser = await p.chromium.launch(channel="chrome")
的await關(guān)鍵字去掉就會(huì)報(bào)錯(cuò)
page = await browser.new_page()
AttributeError: 'coroutine' object has no attribute 'new_page'
sys:1: RuntimeWarning: coroutine 'BrowserType.launch' was never awaited
原因就是代碼行 browser = p.chromium.launch(channel="chrome")還沒(méi)執(zhí)行完就執(zhí)行了下一行 page = await browser.new_page()
最后的總結(jié),如果大家需要并行執(zhí)行用例,那么需要考慮async (這里建議基于場(chǎng)景設(shè)計(jì)),如果沒(méi)有這個(gè)需求,這部分只是點(diǎn)做為了解即可。
我的每一篇文章都希望幫助讀者解決實(shí)際工作中遇到的問(wèn)題!如果文章幫到了您,勞煩點(diǎn)贊、收藏、轉(zhuǎn)發(fā)!您的鼓勵(lì)是我不斷更新文章最大的動(dòng)力!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-656832.html
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-656832.html
到了這里,關(guān)于詳解async 與 await,帶您理解Playwright使用異步方法的正確姿勢(shì)!的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!