詳解async 與 await,帶您理解Playwright使用異步方法的正確姿勢!

大家在使用python做playwright自動化測試的過程中,一定會發(fā)現(xiàn)下面這種異步用法

async def func():

? ? ? await api

? ? ? await api

很多同學可能只是按照這種寫法來編寫項目的自動化測試代碼,對于具體細節(jié)可能并不了解,今天我就來講一下playwright異步用法的相關技術細節(jié)。建議大家拷貝文檔中的腳本實際運行一下,學習的效果會更好!

同步和異步的概念

同步:發(fā)送一個請求,等待返回,然后再發(fā)送下一個請求

異步:發(fā)送一個請求,不等待返回,隨時可以再發(fā)送下一個請求

async 與 await

python在3.5以后引入async和await來強化自身的異步編程,提升效率。async 是異步的簡寫,而 await 可以認為是 async wait 的簡寫。async 用于申明一個 function 是異步的,而 await 用于等待一個異步方法執(zhí)行完成。異步函數(shù)的特點是能在函數(shù)執(zhí)行過程中掛起,去執(zhí)行其他異步函數(shù),等到掛起條件結(jié)束后再回來繼續(xù)執(zhí)行。await的作用是掛起函數(shù),等待函數(shù)操作完成,這時候回去執(zhí)行其他的異步函數(shù),而不是傻等,等掛起的執(zhí)行完成以后將會從其他異步函數(shù)處返回,執(zhí)行掛起結(jié)束的函數(shù)。await只可以對異步函數(shù)使用,普通函數(shù)使用會報錯。await的本質(zhì)是通過yield from 實現(xiàn)的,關于yield生成器相關知識點這里就不詳細介紹了。

例如:兩個異步程序async a、async b:

a中一步有await,當程序碰到關鍵字await后,異步程序a掛起,去執(zhí)行異步b程序(就相當于從一個函數(shù)內(nèi)部跳出去執(zhí)行其他函數(shù));當掛起條件結(jié)束時候,不管b是否執(zhí)行完,要馬上從b程序中跳出來,回到原程序a執(zhí)行原來的操作;如果await后面跟的b函數(shù)不是異步函數(shù),那么操作就只能等b執(zhí)行完再返回,無法在b執(zhí)行的過程中返回,這樣就相當于直接調(diào)用b函數(shù),沒必要使用await關鍵字了。因此,需要await后面跟的是異步函數(shù)。

舉個例子

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ù)加入事件隊列

tasks = [

? ? wait1(),

? ? wait3(),

? ? wait5(),

]

if __name__ == '__main__':

? ? # 創(chuàng)建一個事件循環(huán)

? ? loop = asyncio.get_event_loop()

? ? startTime = time.time()

? ? # 執(zhí)行隊列實踐,直到最晚的一個事件被處理完畢后結(jié)束

? ? loop.run_until_complete(asyncio.wait(tasks))

? ? # 如果不在使用loop,建議使用關閉,類似操作文件的close()函數(shù)

? ? loop.close()

? ? endTime = time.time()

? ? print("sum time: ",endTime-startTime)

運行結(jié)果

wait5 start

wait3 start

wait1 start

wait1 end

wait3 end

wait5 end

sum time:? 5.000609874725342

上面這段代碼大家可以多執(zhí)行幾次,我們會發(fā)現(xiàn):不管wait1 wait3,wait5 哪個函數(shù)先執(zhí)行,但是最后end的順序一定是 wait1>wait3>wait5。一共運行的時間 在5s左右,充分地證明了三個函數(shù)是并行執(zhí)行的!

接下來,我們可以對代碼進行如下修改:

async def wait3():

? ? print('wait3 start')

? ? time.sleep(3)

? ? print('wait3 end')

然后再次運行代碼,結(jié)果如下:

wait5 start

wait3 start

wait3 end

wait1 start

wait1 end

wait5 end

sum time:? 5.002418518066406

大家會發(fā)現(xiàn),只有wait3 end 發(fā)生后,才會出現(xiàn)wait1 end 和wait5 end(),很好的證明了上面的話:如果await后面跟的b函數(shù)不是異步函數(shù),那么操作就只能等b執(zhí)行完再返回,無法在b執(zhí)行的過程中返回,這樣就相當于直接調(diào)用b函數(shù),沒必要使用await關鍵字了。我們可以任意調(diào)整task的執(zhí)行順序,例如:

tasks = [

? ? wait1(),

? ? wait5(),

? ? wait3(),

]

執(zhí)行最慢的情況就是,wait3 第一個start,等待wait3 end后,才能執(zhí)行wait1 或者wait5

wait3 start

wait3 end

wait5 start

wait1 start

wait1 end

wait5 end

sum time:? 8.000799894332886

一個易犯的錯誤

當我們在同步方法中加入await,執(zhí)行代碼的時候會報錯,也就是說像下面這樣編寫playwright腳步是不對的,因為sync_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使用異步方法的正確姿勢

如下代碼會正常運行,通過await可以保證腳本的運行順序

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關鍵字去掉就會報錯

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")還沒執(zhí)行完就執(zhí)行了下一行 page = await browser.new_page()

最后的總結(jié),如果大家需要并行執(zhí)行用例,那么需要考慮async (這里建議基于場景設計),如果沒有這個需求,這部分只是點做為了解即可。

我的每一篇文章都希望幫助讀者解決實際工作中遇到的問題!如果文章幫到了您,勞煩點贊、收藏、轉(zhuǎn)發(fā)!您的鼓勵是我不斷更新文章最大的動力!

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內(nèi)容