面试题答案
一键面试关键技术点
- 异步编程模型:
- 使用
asyncio
库,它是Python中用于编写异步代码的标准库。asyncio
基于事件循环(Event Loop
),可以注册和管理多个异步任务。例如:
import asyncio async def async_task(): await asyncio.sleep(1) return "Task completed" loop = asyncio.get_event_loop() result = loop.run_until_complete(async_task()) print(result)
- 使用
- 异步套接字:
asyncio
提供了asyncio.streams
模块来处理异步套接字。open_connection
函数可以创建异步的TCP连接,start_server
函数可以启动异步TCP服务器。例如,创建一个简单的异步TCP服务器:
import asyncio async def handle_connection(reader, writer): data = await reader.read(1024) message = data.decode('utf - 8') addr = writer.get_extra_info('peername') print(f"Received {message} from {addr}") writer.write(data) await writer.drain() writer.close() async def main(): server = await asyncio.start_server(handle_connection, '127.0.0.1', 8888) async with server: await server.serve_forever() asyncio.run(main())
- 任务管理与调度:
- 使用
asyncio.create_task
来创建任务。多个任务可以同时在事件循环中运行,通过await
关键字暂停任务,允许事件循环切换到其他任务。例如:
import asyncio async def task1(): await asyncio.sleep(2) print("Task 1 completed") async def task2(): await asyncio.sleep(1) print("Task 2 completed") async def main(): task1_obj = asyncio.create_task(task1()) task2_obj = asyncio.create_task(task2()) await task1_obj await task2_obj asyncio.run(main())
- 使用
- 连接池:
- 对于频繁的网络请求,可以创建连接池来复用连接,减少连接建立和关闭的开销。虽然
asyncio
本身没有内置连接池,但可以基于第三方库如aiomysql
(用于MySQL数据库连接池)等实现。例如,使用aiomysql
创建连接池:
import aiomysql async def main(): pool = await aiomysql.create_pool( host='127.0.0.1', port=3306, user='root', password='password', db='test', autocommit=True ) async with pool.acquire() as conn: async with conn.cursor() as cur: await cur.execute("SELECT VERSION()") result = await cur.fetchone() print(result) pool.close() await pool.wait_closed() asyncio.run(main())
- 对于频繁的网络请求,可以创建连接池来复用连接,减少连接建立和关闭的开销。虽然
可能遇到的问题及解决方案
- 资源竞争:
- 问题:多个异步任务同时访问和修改共享资源(如共享变量、文件等)可能导致数据不一致。
- 解决方案:使用锁(
asyncio.Lock
)来保护共享资源。例如:
import asyncio lock = asyncio.Lock() shared_variable = 0 async def increment(): global shared_variable async with lock: shared_variable += 1 await asyncio.sleep(0) print(f"Incremented, value: {shared_variable}") async def main(): tasks = [increment() for _ in range(10)] await asyncio.gather(*tasks) asyncio.run(main())
- 异常处理:
- 问题:异步任务中抛出的异常如果不妥善处理,可能导致整个事件循环崩溃。
- 解决方案:在任务中使用
try - except
块捕获异常,或者在await
任务时捕获异常。例如:
import asyncio async def task_with_exception(): raise ValueError("Simulated error") async def main(): try: await task_with_exception() except ValueError as e: print(f"Caught exception: {e}") asyncio.run(main())
- 内存泄漏:
- 问题:如果不正确地管理异步任务,例如任务持有大量未释放的资源(如文件句柄、网络连接等),可能导致内存泄漏。
- 解决方案:确保在任务完成后,正确释放所有资源。对于连接池,要确保连接在不再使用时正确归还到池中。例如,在关闭异步TCP连接时,调用
writer.close()
和await writer.wait_closed()
。
- 性能瓶颈:
- 问题:过多的任务或复杂的异步操作可能导致事件循环的调度开销过大,成为性能瓶颈。
- 解决方案:对任务进行合理分组和优先级设置。对于一些计算密集型任务,可以考虑使用
concurrent.futures.ProcessPoolExecutor
或concurrent.futures.ThreadPoolExecutor
结合asyncio
来处理,将计算任务放到单独的进程或线程中执行,避免阻塞事件循环。例如:
import asyncio import concurrent.futures def cpu_bound_task(): result = 0 for i in range(1000000): result += i return result async def main(): loop = asyncio.get_running_loop() with concurrent.futures.ProcessPoolExecutor() as executor: result = await loop.run_in_executor(executor, cpu_bound_task) print(f"Result: {result}") asyncio.run(main())