面试题答案
一键面试Python中asyncio库实现异步I/O的原理
- 事件循环(Event Loop):
- asyncio的核心是事件循环。事件循环是一个无限循环,它负责管理和调度异步任务。它会不断地检查是否有任务需要执行,一旦有任务准备好(例如I/O操作完成),就会将其加入到执行队列中并执行。
- 应用程序通过将协程(coroutine)注册到事件循环中,事件循环按照一定的规则来调度这些协程的执行。
- 协程(Coroutine):
- 在Python中,使用
async def
定义的函数就是协程。协程是一种特殊的函数,它可以暂停执行并将控制权交回给事件循环,当满足特定条件(如I/O操作完成)时,再从暂停的地方恢复执行。 - 协程本身并不执行,需要通过事件循环来驱动执行。例如:
async def my_coroutine(): await asyncio.sleep(1) print('Coroutine resumed')
- 这里
await
关键字用于暂停协程的执行,直到所等待的asyncio.sleep(1)
(模拟I/O操作)完成,然后再恢复执行协程后面的代码。
- 在Python中,使用
- 任务(Task):
- 任务是对协程的进一步封装,它被用于将协程加入到事件循环中执行。
asyncio.create_task()
方法可以将一个协程包装成一个任务并提交到事件循环中。 - 任务有自己的状态,如
PENDING
(未开始执行)、RUNNING
(正在执行)、DONE
(执行完成)等。事件循环会根据任务的状态来调度任务的执行。例如:
async def my_coroutine(): await asyncio.sleep(1) return 'Result' async def main(): task = asyncio.create_task(my_coroutine()) result = await task print(result)
- 任务是对协程的进一步封装,它被用于将协程加入到事件循环中执行。
- 异步I/O原语:
- asyncio提供了一些用于异步I/O操作的原语,如
asyncio.sleep()
用于模拟I/O延迟,asyncio.open_connection()
用于异步网络连接等。这些原语在执行时会暂停协程,将控制权交回给事件循环,以便事件循环可以调度其他任务执行,从而实现异步I/O。
- asyncio提供了一些用于异步I/O操作的原语,如
在网络爬虫项目中利用asyncio库高效抓取多个网页内容并处理网络异常
- 安装必要的库:
- 除了
asyncio
本身是Python标准库外,还需要安装aiohttp
库来进行异步HTTP请求。可以使用pip install aiohttp
进行安装。
- 除了
- 编写异步抓取函数:
import asyncio import aiohttp async def fetch(session, url): try: async with session.get(url) as response: if response.status == 200: return await response.text() else: print(f'Error: {response.status} for {url}') return None except aiohttp.ClientError as e: print(f'Network error for {url}: {e}') return None async def fetch_all(urls): async with aiohttp.ClientSession() as session: tasks = [fetch(session, url) for url in urls] results = await asyncio.gather(*tasks) return results def main(): urls = ['http://example.com', 'http://example.org', 'http://example.net'] loop = asyncio.get_event_loop() try: content = loop.run_until_complete(fetch_all(urls)) for i, c in enumerate(content): if c: print(f'Content for {urls[i]}:\n{c}') finally: loop.close() if __name__ == '__main__': main()
- 在上述代码中:
fetch
函数负责单个URL的抓取,它使用aiohttp.ClientSession
进行异步HTTP GET请求。如果请求成功(状态码为200),则返回网页内容;否则打印错误信息。同时,通过try - except
块捕获aiohttp.ClientError
异常来处理可能出现的网络异常,如连接超时、DNS解析失败等。fetch_all
函数创建多个fetch
任务,并使用asyncio.gather
并发执行这些任务,等待所有任务完成并返回结果列表。main
函数定义了要抓取的URL列表,获取事件循环,运行fetch_all
函数并处理结果,最后关闭事件循环。
- 在上述代码中:
通过上述方式,可以利用asyncio
库高效地抓取多个网页内容,并通过适当的异常处理机制处理可能出现的网络异常。