面试题答案
一键面试async
关键字作用
- 定义异步函数:在Python中,使用
async
关键字来定义一个异步函数。异步函数在调用时,并不会立即执行函数体中的代码,而是返回一个coroutine
对象。例如:
async def async_function():
print('这是一个异步函数')
- 表明函数是异步可挂起的:异步函数内可以包含
await
表达式,这使得函数在执行到await
时可以暂停执行,将控制权交回给事件循环,直到被await
的coroutine
完成。
await
关键字作用
- 暂停异步函数执行:
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)
- 获取
coroutine
的返回值:await
表达式会返回被等待的coroutine
的返回值。在上述例子中,await inner_async()
会等待inner_async
执行完毕,并将其返回值赋给result
。
使用asyncio
创建简单异步任务
- 创建异步函数:首先定义一个或多个异步函数,如:
import asyncio
async def task_function():
print('开始执行任务')
await asyncio.sleep(2)
print('任务执行完成')
- 创建事件循环并运行任务:使用
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场景下相较于线程的优势
- 资源消耗低:线程的创建和销毁需要消耗较多的系统资源,每个线程都需要占用一定的栈空间等。而
asyncio
基于协程,在用户态进行调度,不需要像线程那样切换上下文,创建和销毁的开销小,适合处理大量并发任务。例如,创建数以万计的线程可能会导致系统资源耗尽,但使用asyncio
创建数以万计的协程任务则相对轻松。 - 避免全局解释器锁(GIL)限制:在Python中,由于GIL的存在,同一时刻只有一个线程能执行Python字节码,这使得多线程在CPU密集型任务中无法充分利用多核优势。而
asyncio
的异步编程模型是基于事件循环和协程,不存在GIL的限制,在I/O密集型场景下可以更高效地利用系统资源,提升并发性能。 - 代码逻辑相对简单:线程编程中,为了保证数据的一致性和避免竞态条件,需要使用锁、信号量等同步机制,这使得代码变得复杂且容易出错。
asyncio
通过异步函数和await
关键字,以更线性的方式编写异步代码,代码逻辑相对清晰,更易于理解和维护。