详解async 与 await,带您理解Playwright使用异步方法的正确姿势!

大家在使用python做playwright自动化测试的过程中,一定会发现下面这种异步用法

async def func():
      await api
      await api

很多同学可能只是按照这种写法来编写项目的自动化测试代码,对于具体细节可能并不了解,今天我就来讲一下playwright异步用法的相关技术细节。建议大家拷贝文档中的脚本实际运行一下,学习的效果会更好!

同步和异步的概念

同步:发送一个请求,等待返回,然后再发送下一个请求
异步:发送一个请求,不等待返回,随时可以再发送下一个请求

async 与 await

python在3.5以后引入async和await来强化自身的异步编程,提升效率。async 是异步的简写,而 await 可以认为是 async wait 的简写。async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。异步函数的特点是能在函数执行过程中挂起,去执行其他异步函数,等到挂起条件结束后再回来继续执行。await的作用是挂起函数,等待函数操作完成,这时候回去执行其他的异步函数,而不是傻等,等挂起的执行完成以后将会从其他异步函数处返回,执行挂起结束的函数。await只可以对异步函数使用,普通函数使用会报错。await的本质是通过yield from 实现的,关于yield生成器相关知识点这里就不详细介绍了。

例如:两个异步程序async a、async b:

a中一步有await,当程序碰到关键字await后,异步程序a挂起,去执行异步b程序(就相当于从一个函数内部跳出去执行其他函数);当挂起条件结束时候,不管b是否执行完,要马上从b程序中跳出来,回到原程序a执行原来的操作;如果await后面跟的b函数不是异步函数,那么操作就只能等b执行完再返回,无法在b执行的过程中返回,这样就相当于直接调用b函数,没必要使用await关键字了。因此,需要await后面跟的是异步函数。

举个例子

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)

运行结果

wait5 start

wait3 start

wait1 start

wait1 end

wait3 end

wait5 end

sum time: 5.000609874725342

上面这段代码大家可以多执行几次,我们会发现:不管wait1 wait3,wait5 哪个函数先执行,但是最后end的顺序一定是 wait1>wait3>wait5。一共运行的时间 在5s左右,充分地证明了三个函数是并行执行的!

接下来,我们可以对代码进行如下修改:

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

然后再次运行代码,结果如下:

wait5 start

wait3 start

wait3 end

wait1 start

wait1 end

wait5 end

sum time: 5.002418518066406

大家会发现,只有wait3 end 发生后,才会出现wait1 end 和wait5 end(),很好的证明了上面的话:如果await后面跟的b函数不是异步函数,那么操作就只能等b执行完再返回,无法在b执行的过程中返回,这样就相当于直接调用b函数,没必要使用await关键字了。我们可以任意调整task的执行顺序,例如:

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

执行最慢的情况就是,wait3 第一个start,等待wait3 end后,才能执行wait1 或者wait5

wait3 start

wait3 end

wait5 start

wait1 start

wait1 end

wait5 end

sum time: 8.000799894332886

一个易犯的错误

当我们在同步方法中加入await,执行代码的时候会报错,也就是说像下面这样编写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")还没执行完就执行了下一行 page = await browser.new_page()

最后的总结,如果大家需要并行执行用例,那么需要考虑async (这里建议基于场景设计),如果没有这个需求,这部分只是点做为了解即可。

我的每一篇文章都希望帮助读者解决实际工作中遇到的问题!如果文章帮到了您,劳烦点赞、收藏、转发!您的鼓励是我不断更新文章最大的动力!

 

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
C#中的async和await关键字是用来实现异步编程的。它们的作用是让开发人员能够更方便地处理异步任务。async关键字可以用来修饰方法,表示该方法是一个异步方法,而await关键字用于等待异步任务的完成。 async和await使用可以帮助我们编写更简洁、易读的异步代码。当我们在一个方法使用async关键字时,编译器会将该方法转换为一个状态机。这样,当遇到一个耗时的操作时,我们可以使用await关键字来等待该操作完成,而不会阻塞整个线程。当异步操作完成后,代码会继续执行。 async和await使用需要注意一些细节。首先,异步方法必须返回一个Task对象或Task<T>对象,表示异步操作的结果。其次,在异步方法中,可以使用await关键字来等待一个异步操作的完成,但需要在方法的签名中声明async关键字。而且,await关键字只能在异步方法使用。 在使用async和await时,还需注意一些原则。首先,尽量避免在异步方法使用阻塞操作,以充分发挥异步编程的优势。其次,可以使用Task.WhenAll或Task.WhenAny等方法来并行处理多个异步任务。另外,可以使用ConfigureAwait方法来配置异步任务的上下文。 总之,C#中的async和await提供了一种简洁、易读的方式来处理异步任务。通过合理的使用,可以提高代码的性能和可维护性。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

测试开发Kevin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值