面试题答案
一键面试设计思路
- 多线程用于CPU密集型任务:多线程适合处理CPU密集型的辅助任务,例如数据预处理、计算校验和等。因为Python的全局解释器锁(GIL),同一时间只有一个线程能执行Python字节码,所以多线程对于CPU密集型任务并不能真正利用多核优势,但在一些简单计算任务上可以在一定程度上提高效率。
- 异步I/O用于I/O密集型任务:
asyncio
库专门用于处理I/O密集型任务,它通过事件循环、协程和异步函数来实现异步操作。在进行I/O操作(如网络请求、文件读写等)时,协程可以暂停执行,让事件循环去执行其他协程,从而提高I/O操作的并发处理能力。 - 结合方式:将CPU密集型任务放在多线程中执行,将I/O密集型任务使用
asyncio
的异步方式处理。这样可以充分利用多线程和异步I/O的优势,提高项目整体性能。
示例代码
import asyncio
import concurrent.futures
import time
# CPU密集型任务函数
def cpu_bound_task(n):
result = 0
for i in range(n):
result += i
return result
# 异步I/O模拟函数
async def io_bound_task():
await asyncio.sleep(1) # 模拟I/O操作
return "I/O task completed"
async def main():
# 创建线程池
with concurrent.futures.ThreadPoolExecutor() as executor:
loop = asyncio.get_running_loop()
# 提交CPU密集型任务到线程池
cpu_task1 = loop.run_in_executor(executor, cpu_bound_task, 1000000)
cpu_task2 = loop.run_in_executor(executor, cpu_bound_task, 2000000)
# 异步I/O任务
io_task1 = io_bound_task()
io_task2 = io_bound_task()
# 等待所有任务完成
results = await asyncio.gather(cpu_task1, cpu_task2, io_task1, io_task2)
print(results)
if __name__ == "__main__":
start_time = time.time()
asyncio.run(main())
end_time = time.time()
print(f"Total time: {end_time - start_time} seconds")
在上述代码中:
cpu_bound_task
是一个CPU密集型任务函数,通过循环计算累加值。io_bound_task
是一个异步I/O模拟任务,使用asyncio.sleep
模拟I/O操作的等待时间。- 在
main
函数中,使用concurrent.futures.ThreadPoolExecutor
创建线程池,将CPU密集型任务提交到线程池执行,并通过loop.run_in_executor
方法与asyncio
事件循环集成。同时,创建异步I/O任务io_bound_task
,最后使用asyncio.gather
等待所有任务完成并获取结果。
通过这种方式,可以在一个项目中有效结合多线程和异步I/O来提高性能。