请解释 C# 中 ThreadPool 的内部运行机制,包括其线程管理、任务调度和资源分配方式。
考察说明
考查对 C# 线程池内部机制、线程管理和任务调度的理解。
回答思路
- 【回答框架 1】ThreadPool 是 .NET 提供的线程复用机制,核心是维护一个线程池,避免频繁创建销毁线程的开销。它通过全局队列和本地队列管理待执行的工作项,线程从队列中获取任务并执行。
- 【回答框架 2】线程池会根据系统负载和任务数量动态调整线程数。初始线程数通常等于 CPU 核心数,当任务增多且现有线程繁忙时,会逐步增加线程,但受最大线程数限制。增加线程存在延迟,以避免过度创建。
- 【回答框架 3】线程池使用工作窃取算法:每个线程有自己的本地队列,当本地队列为空时,会从其他线程的队列或全局队列中窃取任务,提高负载均衡和缓存局部性。
- 【回答框架 4】线程池中的线程分为工作者线程和 I/O 线程。工作者线程处理 CPU 密集型任务,I/O 线程用于异步 I/O 完成回调,避免阻塞工作者线程。
- 【回答框架 5】线程池通过调度器(如 TaskScheduler)将任务分配给线程,默认调度器基于线程池实现。任务优先级、取消和等待机制由 Task 和线程池协作完成。
- 【关键点 1】线程池复用线程,减少创建销毁开销。
- 【关键点 2】动态调整线程数,初始为 CPU 核心数,受最大线程数限制。
- 【关键点 3】使用工作窃取算法提升负载均衡。
- 【关键点 4】区分工作者线程和 I/O 线程,分别处理计算和异步 I/O。
- 【关键点 5】默认 TaskScheduler 基于线程池实现任务调度。
- 【易错点 1】线程池线程数并非越多越好,过多会增加上下文切换开销。
- 【易错点 2】线程池不保证任务执行顺序,依赖调度策略。
- 【易错点 3】长时间运行的任务可能阻塞线程池,导致饥饿,应使用专用线程或 TaskCreationOptions.LongRunning。