面试题答案
一键面试优化方面
- 调整线程池大小:根据服务器硬件资源(如CPU核心数、内存大小)和任务特性(I/O密集型还是CPU密集型)合理设置线程池大小。对于I/O密集型任务,线程数可适当增大;对于CPU密集型任务,线程数一般设置为CPU核心数或略多一点。
- 任务队列管理:使用有界队列,防止任务无限制堆积导致内存耗尽。根据系统负载和处理能力设置合适的队列大小。
- 线程复用与回收:确保线程在完成任务后能及时被复用,避免频繁创建和销毁线程带来的开销。
- 异常处理:在线程执行任务过程中,妥善处理异常,避免因未处理异常导致线程终止而无法复用。
代码示例
import concurrent.futures
import requests
# 模拟爬取任务
def crawl(url):
try:
response = requests.get(url)
return response.status_code
except Exception as e:
print(f"爬取 {url} 时出错: {e}")
return None
def main():
urls = [
"http://example.com",
"http://example.org",
"http://example.net"
]
# 调整线程池大小,这里假设为CPU核心数的2倍(I/O密集型任务示例)
max_workers = 2 * concurrent.futures.ProcessPoolExecutor()._max_workers
# 使用有界队列,设置队列大小为10
queue = concurrent.futures.Queue(maxsize=10)
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
future_to_url = {executor.submit(crawl, url): url for url in urls}
for future in concurrent.futures.as_completed(future_to_url):
url = future_to_url[future]
try:
status_code = future.result()
if status_code is not None:
print(f"{url} 爬取成功,状态码: {status_code}")
except Exception as e:
print(f"任务处理时发生异常: {e}")
if __name__ == "__main__":
main()
在上述代码中:
max_workers
根据CPU核心数动态调整线程池大小,适用于I/O密集型任务。concurrent.futures.Queue(maxsize=10)
创建了一个有界队列,防止任务无限堆积。- 在
crawl
函数和主循环中进行了异常处理,确保任务异常时不会影响线程复用。