python中async/await异步功能是什么,有什么用?

async/await异步

异步代码的作用是,在程序需要等待操作时(例如读写文件,网络请求等),可以不阻塞程序的执行。这样做可以提升程序的性能以及响应速度。

在python中,这种异步通过“协程”实现,这是一种特殊的函数,可以在执行过程中暂停,并且在需要时恢复,通过关键字async/await定义。

时至今日,仍然有很多python使用者对于该功能不是很了解,下面就将介绍一下,如何使用。

使用方法

定义异步函数

import asyncio

async def async_function():
    print("程序开始运行")
    await asyncio.sleep(2)  # 模拟等待2秒
    print("程序运行结束")
    return "已完成"

调用异步函数

注意,直接调用异步函数是不可行的,这样并不会执行函数。

# 如果按照普通的函数调用,来调用一个异步函数
# 那么返回的结果是一个协程对象,真正的代码不会被执行
async_function()

如果需要调用异步函数,可以使用asyncio.run()

import asyncio

async def main():
    result = await async_function()
    print("异步程序运行结果:", result)

asyncio.run(main())

注意:asyncio.run()需要python3.7的版本,在更早之前通常使用asyncio.get_event_loop()

并发执行

使用asyncio.gather()可以并发执行多个协程。

import asyncio

async def main():
    tasks = [async_function() for i in range(3)]
    result = await asyncio.gather(*tasks)
    print(result)
    
asyncio.run(main())

从这里可以看出,每个程序需要用时2秒,如果阻塞程序依次执行,那么需要用时6秒才能完成。但是,在并发执行的情况下,几乎2秒就可以完成。

异步生成器

异步生成器允许在异步中使用生成器。

import asyncio

async def async_num():
    for i in range(5):
        await asyncio.sleep(2)
        yield i

async def main():
    async for number in async_num():
        print(number)

asyncio.run(main())

同时,异步生成表达式允许在生成器表达式中使用async

async def main():
    async_generator = (i async for i in async_num())
    async for i in async_generator:
        print(i)

同步函数放入独立线程(3.9)

使用asyncio.to_thread()可以将同步函数放入到独立线程之中,避免堵塞

import time
import asyncio

def sync_function(sleep_time, some_data):
    time.sleep(sleep_time)
    return some_data
    
    
async def main():
    result = await asyncio.to_thread(sync_function, 2, "blablablabla")
    print(result)
  
asyncio.run(main())

注意:该方法不能在python3.8中使用,必须在3.9以后版本使用。在更早之前通常需要使用loop.run_in_executor()

回调函数

熟悉异步模型的通常会了解到,异步模型通常是通过回调函数实现的,当一个异步函数执行结束以后,可以选择去执行某个回调函数,例如javascript中的Promise。

实际上,采用了async和await以后,自己绑定回调函数往往是不需要的,但是,很明显,asyncio的机制中是支持回调函数的。

import asyncio


def callback(future):
    print("运行结果为:", future.result())

async def async_function():
    print("程序开始运行")
    await asyncio.sleep(2)
    print("程序运行结束")
    return "已完成"


async def main():
    task = asyncio.create_task(async_function())
    task.add_done_callback(callback)
    await task
    
    
asyncio.run(main())

实际上,之前已经介绍过了,无需使用回调函数,使用await,就可以完成相同的效果:

import asyncio

async def async_function():
    print("程序开始运行")
    await asyncio.sleep(2)
    print("程序运行结束")
    return "已完成"


async def main():
    result = await async_function()
    print("运行结果为:", result)    
    
asyncio.run(main())

在更早期的版本中(python3.4)是没有async以及await,当时需要通过@asyncio.coroutine装饰器定义异步函数,但是该方法于python3.8已废弃,因此不再进行额外介绍。

异步网络请求

传统的requests库是一个同步的网络库,并不适合用于发送异步请求,如果要发送异步请求,最好需要使用aiohttp。

import asyncio
import aiohttp

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = ['https://httpbin.org/get'] * 10  # 模拟多个请求
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        print(len(results))
        print(results[0])

        
if __name__ == "__main__":
    asyncio.run(main())

与多线程的区别

异步编程,async/await不是多线程,它是在同一个线程中,实际上是单线程的事件循环。当遇到等待操作,允许程序继续执行其他任务,而不阻塞整个程序运行。而多线程是同时启用了多个线程,在启用大量线程时,需要更多资源。

一般来说,在I/O密集的任务中,异步编程通常更高效,因为避免了多线程切换的开销和损耗。但是其在单一线程中,无法利用多核cpu,因此不适用于cpu密集型任务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值