MST

星途 面试题库

面试题:Python线程替代方案中的异步编程

`asyncio`是Python进行异步编程的库,常被视为线程的替代方案之一。请详细阐述`asyncio`中`async`、`await`关键字的作用,以及如何使用`asyncio`创建一个简单的异步任务,并说明它在高并发I/O场景下相较于线程的优势。
23.7万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

async关键字作用

  1. 定义异步函数:在Python中,使用async关键字来定义一个异步函数。异步函数在调用时,并不会立即执行函数体中的代码,而是返回一个coroutine对象。例如:
async def async_function():
    print('这是一个异步函数')
  1. 表明函数是异步可挂起的:异步函数内可以包含await表达式,这使得函数在执行到await时可以暂停执行,将控制权交回给事件循环,直到被awaitcoroutine完成。

await关键字作用

  1. 暂停异步函数执行await只能在async定义的函数内部使用。当执行到await时,它会暂停当前异步函数的执行,等待一个coroutine对象完成(通常是I/O操作完成)。例如:
import asyncio

async def inner_async():
    await asyncio.sleep(1)
    return '内部异步函数完成'

async def outer_async():
    result = await inner_async()
    print(result)
  1. 获取coroutine的返回值await表达式会返回被等待的coroutine的返回值。在上述例子中,await inner_async()会等待inner_async执行完毕,并将其返回值赋给result

使用asyncio创建简单异步任务

  1. 创建异步函数:首先定义一个或多个异步函数,如:
import asyncio

async def task_function():
    print('开始执行任务')
    await asyncio.sleep(2)
    print('任务执行完成')
  1. 创建事件循环并运行任务:使用asyncio.get_event_loop()获取事件循环对象,然后使用loop.run_until_complete()方法来运行异步任务。例如:
loop = asyncio.get_event_loop()
try:
    loop.run_until_complete(task_function())
finally:
    loop.close()

在Python 3.7及以上版本,还可以使用更简洁的asyncio.run()来运行异步任务:

async def task_function():
    print('开始执行任务')
    await asyncio.sleep(2)
    print('任务执行完成')

asyncio.run(task_function())

在高并发I/O场景下相较于线程的优势

  1. 资源消耗低:线程的创建和销毁需要消耗较多的系统资源,每个线程都需要占用一定的栈空间等。而asyncio基于协程,在用户态进行调度,不需要像线程那样切换上下文,创建和销毁的开销小,适合处理大量并发任务。例如,创建数以万计的线程可能会导致系统资源耗尽,但使用asyncio创建数以万计的协程任务则相对轻松。
  2. 避免全局解释器锁(GIL)限制:在Python中,由于GIL的存在,同一时刻只有一个线程能执行Python字节码,这使得多线程在CPU密集型任务中无法充分利用多核优势。而asyncio的异步编程模型是基于事件循环和协程,不存在GIL的限制,在I/O密集型场景下可以更高效地利用系统资源,提升并发性能。
  3. 代码逻辑相对简单:线程编程中,为了保证数据的一致性和避免竞态条件,需要使用锁、信号量等同步机制,这使得代码变得复杂且容易出错。asyncio通过异步函数和await关键字,以更线性的方式编写异步代码,代码逻辑相对清晰,更易于理解和维护。