面试题答案
一键面试多线程、多进程与异步I/O优缺点对比
- 多线程
- 优点:
- 线程创建和销毁开销相对较小,上下文切换比进程快,能快速响应新的客户端连接。
- 线程间共享进程资源,方便数据共享和通信,在处理某些需要共享数据的任务时很方便。
- 缺点:
- 由于Python的全局解释器锁(GIL),在CPU密集型任务中,多线程无法利用多核CPU优势,不能真正实现并行计算。
- 多线程编程容易出现死锁问题,当多个线程竞争共享资源且获取资源顺序不一致时可能导致死锁。
- 线程之间的同步和通信需要复杂的锁机制,增加了编程复杂度。
- 优点:
- 多进程
- 优点:
- 每个进程有独立的内存空间,不存在GIL限制,能充分利用多核CPU进行并行计算,适合CPU密集型任务。
- 进程间相互独立,一个进程崩溃不会影响其他进程,稳定性较高。
- 缺点:
- 进程创建和销毁开销大,启动时间长,在处理大量并发连接时资源消耗大。
- 进程间通信相对复杂,不像线程间共享资源那样方便,通常需要使用管道、消息队列等方式进行通信。
- 优点:
- 异步I/O(asyncio)
- 优点:
- 基于事件循环,单线程实现异步操作,避免了多线程和多进程的资源开销,适合I/O密集型任务,能高效处理大量并发连接。
- 代码结构相对简单,通过
async/await
语法使异步代码看起来更像是同步代码,易于理解和维护。
- 缺点:
- 由于是单线程执行,对于CPU密集型任务无法利用多核优势。
- 调试相对复杂,因为异步操作的执行顺序可能不直观,排查问题时需要对事件循环机制有深入理解。
- 优点:
异步I/O(asyncio)实现多并发客户端连接服务器代码示例
import asyncio
async def handle_connection(reader, writer):
while True:
try:
data = await reader.read(1024)
if not data:
break
message = data.decode('utf - 8')
print(f"Received {message} from {writer.get_extra_info('peername')}")
response = f"Server received: {message}"
writer.write(response.encode('utf - 8'))
await writer.drain()
except ConnectionResetError:
break
writer.close()
await writer.wait_closed()
async def main():
server = await asyncio.start_server(handle_connection, '127.0.0.1', 8888)
async with server:
await server.serve_forever()
if __name__ == "__main__":
asyncio.run(main())
上述代码使用asyncio
库创建了一个简单的异步服务器。handle_connection
函数处理每个客户端连接,从客户端读取数据,打印并回复一条包含接收到消息的响应。main
函数启动服务器并使其持续运行,监听本地地址127.0.0.1
的8888
端口。asyncio.run
函数用于运行异步函数main
。