Explain async and await in detail, and take you to understand the correct posture of Playwright to use asynchronous methods!

In the process of using python to do playwright automated testing, you will definitely find the following asynchronous usage

async def func():
      await api
      await api

Many students may just write the automated test code of the project according to this way of writing, and may not understand the specific details. Today I will talk about the technical details related to the asynchronous usage of playwright. It is recommended that you copy the script in the document and actually run it, the learning effect will be better!

Synchronous and asynchronous concepts

Synchronous: Send a request, wait for the return, and then send the next request
Asynchronous: Send a request, do not wait for the return, you can send the next request at any time

async and await

Python introduced async and await after 3.5 to strengthen its own asynchronous programming and improve efficiency. async is shorthand for asynchronous, and await can be thought of as shorthand for async wait. async is used to declare that a function is asynchronous, and await is used to wait for an asynchronous method to complete. The feature of an asynchronous function is that it can be suspended during function execution to execute other asynchronous functions, and then return to continue execution after the suspension condition ends. The function of await is to suspend the function and wait for the function operation to complete. At this time, go back and execute other asynchronous functions instead of waiting stupidly. After the suspended execution is completed, it will return from other asynchronous functions and execute the suspended function. await can only be used for asynchronous functions, and an error will be reported when using ordinary functions. The essence of await is realized through yield from, and the knowledge points related to yield generator will not be introduced in detail here.

For example: two asynchronous programs async a, async b:

There is await in one step of a, when the program encounters the keyword await, the asynchronous program a hangs up to execute the asynchronous b program (equivalent to jumping out of a function to execute other functions); when the suspension condition ends, regardless of b Whether or not the execution is completed, jump out of the b program immediately, return to the original program a to execute the original operation; if the b function followed by await is not an asynchronous function, then the operation can only wait for b to finish executing before returning, and cannot be executed in b Return in the process, which is equivalent to calling the b function directly, and there is no need to use the await keyword. Therefore, await is followed by an asynchronous function.

for example

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. 将异步函数加入事件队列

tasks = [
    wait1(),
    wait3(),
    wait5(),
]

if __name__ == '__main__':

    # 创建一个事件循环
    loop = asyncio.get_event_loop()
    startTime = time.time()
    # 执行队列实践,直到最晚的一个事件被处理完毕后结束
    loop.run_until_complete(asyncio.wait(tasks))
    # 如果不在使用loop,建议使用关闭,类似操作文件的close()函数
    loop.close()
    endTime = time.time()
    print("sum time: ",endTime-startTime)

operation result

wait5 start

wait3 start

wait1 start

wait1 end

wait3 end

wait5 end

sum time: 5.000609874725342

You can execute the above code several times, and we will find that no matter which function wait1, wait3, or wait5 is executed first, the order of the final end must be wait1>wait3>wait5. The total running time is about 5s, which fully proves that the three functions are executed in parallel!

Next, we can modify the code as follows:

async def wait3():
    print('wait3 start')
    time.sleep(3)
    print('wait3 end')

Then run the code again, the result is as follows:

wait5 start

wait3 start

wait3 end

wait1 start

wait1 end

wait5 end

sum time: 5.002418518066406

You will find that only after wait3 end occurs, wait1 end and wait5 end() will appear, which proves the above statement well: if the b function followed by await is not an asynchronous function, then the operation can only wait for b to finish executing Return cannot be returned during the execution of b, which is equivalent to calling the b function directly, and there is no need to use the await keyword. We can adjust the execution order of tasks arbitrarily, for example:

tasks = [
    wait1(),
    wait5(),
    wait3(),
]

The slowest execution is that the first start of wait3 waits for the end of wait3 before executing wait1 or wait5

wait3 start

wait3 end

wait5 start

wait1 start

wait1 end

wait5 end

sum time: 8.000799894332886

an easy mistake

When we add await to the synchronization method, an error will be reported when the code is executed, that is to say, it is wrong to write the playwright script like the following, because sync_playwright() is a synchronization method!

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's correct posture for using asynchronous methods

The following code will run normally, and the order of script execution can be guaranteed by 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())

If we remove the await keyword of browser = await p.chromium.launch(channel= "chrome" ) in the above code, an error will be reported

page = await browser.new_page()

AttributeError: 'coroutine' object has no attribute 'new_page'

sys:1: RuntimeWarning: coroutine 'BrowserType.launch' was never awaited

The reason is that the code line browser = p.chromium.launch(channel= "chrome" ) is executed before the next line page = await browser.new_page()

The final summary, if you need to execute use cases in parallel, you need to consider async (here is recommended based on scenario design), if there is no such requirement, this part is just for understanding.

Every article of mine hopes to help readers solve problems encountered in actual work! If the article helped you, please like, bookmark, forward! Your encouragement is my biggest motivation to keep updating articles!

 

Guess you like

Origin blog.csdn.net/liwenxiang629/article/details/130555814