es thread_pool esthreadpool 线程不够_threadpool

es thread_pool esthreadpool 线程不够_es thread_pool_02


📣读完这篇文章里你能收获到

  • 了解线程池不足的常见现象
  • 解析引起线程池不足的原因
  • 根据不同的需求场景提出不同的优化措施
  • 感谢点赞+收藏,避免下次找不到~

es thread_pool esthreadpool 线程不够_es thread_pool_02


文章目录

  • 一、ThreadPool 资源不足会有引起哪些现象
  • 二、导致 ThreadPool 资源不足的常见原因
  • 三、调优 ThreadPool 的措施
  • 1. 使用异步编程模型
  • 2. 使用 Task.Factory.StartNew
  • 3. 长时间运行的任务处理
  • 4. 合理设置线程池参数
  • 四、.NET中如何合理设置线程池参数
  • 1. 线程池最大线程数
  • 2. 线程池最小线程数
  • 3. 线程池队列长度
  • 4. 线程池工作线程优先级


es thread_pool esthreadpool 线程不够_es thread_pool_02

一、ThreadPool 资源不足会有引起哪些现象

  1. 任务执行时间变长:由于Task.Run 和 ThreadPool.QueueUserWorkItem 都是将任务提交给线程池执行,当线程池中的工作线程不足时,需要等待其他任务执行完成后才能得到执行,因此会导致整体的任务执行时间会变长。
  2. 程序崩溃:如果线程池中没有可用的工作线程,新的任务将无法得到执行,从而导致程序崩溃或出现异常。
  3. 内存泄漏:如果使用了大量的异步任务,而线程池中的工作线程数不足,会导致这些任务一直在等待线程池资源,从而占用大量的内存资源,引发内存泄漏。
  4. 服务器性能下降:如果是 Web 应用程序,当线程池资源不足时,可能会导致服务器的性能下降,响应时间变长,甚至无法响应客户端请求。

es thread_pool esthreadpool 线程不够_es thread_pool_02

二、导致 ThreadPool 资源不足的常见原因

  1. 阻塞操作:如果您的代码中存在阻塞操作(例如 I/O 操作),并且这些操作使用了同步方式,这可能会导致线程池中的线程被阻塞。当线程被阻塞时,它不能被用于执行其他任务,从而导致线程池资源不足。
  2. 长时间运行的任务:如果您的代码中存在长时间运行的任务(例如计算密集型操作),这可能会导致线程池中的线程被占用。当线程被占用时,它不能被用于执行其他任务,从而导致线程池资源不足。
  3. 不恰当的线程使用:如果您的代码中创建了大量的线程(例如使用 Thread 类),而不是使用线程池,这可能会导致线程池资源不足。因为线程池的目的是重复使用线程来执行任务,如果您自己创建线程,则会降低线程池的效率。
  4. 线程泄漏:如果您的代码中存在线程泄漏(例如线程未正确释放),这可能会导致线程池资源不足。因为线程池中的线程是有限的,如果您的代码中存在泄漏的线程,则这些线程将一直占用线程池资源,直到应用程序退出。

es thread_pool esthreadpool 线程不够_es thread_pool_02

三、调优 ThreadPool 的措施

1. 使用异步编程模型

  • 使用 async/await:使用异步编程模型,可以避免线程被阻塞,从而释放线程池资源。
//【避免】会阻止线程,这是导致 ThreadPool 资源不足的最常见原因
Customer c = PretendQueryCustomerFromDbAsync("Dana").Result;

//【建议】使用 await 可让当前线程在数据库查询过程中为其他工作项提供服务
Customer c = await PretendQueryCustomerFromDbAsync("Dana");

2. 使用 Task.Factory.StartNew

  • 使用 Task.Factory.StartNew 方法:可以使用 Task.Factory.StartNew 方法,手动创建一个新的任务,而不是使用线程池中的工作者线程执行任务,以避免线程池资源不足导致任务无法执行的情况
Task.Factory.StartNew(() => {
    // 执行任务
});

3. 长时间运行的任务处理

  • 尽可能避免长时间运行的任务:尽可能使用短时间运行的任务,避免使用计算密集型操作,如需长时间运行任务(比如与应用生命周期相同),可以通过在调用 Task.Factory.StartNew 方法时传入 TaskCreationOptions.LongRunning 参数,可以通知 TaskScheduler 创建一个新线程来执行该任务。这种方式可以避免使用线程池线程来执行长时间运行的任务,从而避免线程池资源不足的情况。
Task.Factory.StartNew(() => {
    // 执行长时间运行的任务
}, TaskCreationOptions.LongRunning);

4. 合理设置线程池参数

  • 参考以下

es thread_pool esthreadpool 线程不够_es thread_pool_02

四、.NET中如何合理设置线程池参数

1. 线程池最大线程数

  • 应根据应用程序的负载情况来设置,以确保最大限度地利用计算资源。在设置最大线程数时,应该考虑到应用程序中存在的所有线程和其他系统资源的使用情况。
//将线程池的最大工作者线程数设置为当前最大线程数的两倍
int workerThreads, completionPortThreads;
ThreadPool.GetMaxThreads(out workerThreads, out completionPortThreads);
ThreadPool.SetMaxThreads(workerThreads * 2, completionPortThreads);

2. 线程池最小线程数

  • 应根据应用程序的负载情况来设置,以确保始终有足够的线程可用于执行任务。一般情况下,线程池最小线程数应该设置为 0,以允许线程池动态调整线程数。
//将线程池的最小工作者线程数和 I/O 完成端口线程数都设置为 10。
ThreadPool.SetMinThreads(10, 10);

3. 线程池队列长度

  • 应根据应用程序的负载情况来设置。队列长度应该设置得足够大,以容纳瞬时的任务突发,并允许线程池动态调整队列长度。
//将线程池的队列长度设置为 1000
ThreadPool.SetMaxQueuedWorkItems(1000);

4. 线程池工作线程优先级

  • 应根据应用程序的性能要求和响应时间要求来设置。如果应用程序需要高性能,可以将线程池工作者线程的优先级设置为 ThreadPriority.AboveNormal 或 ThreadPriority.Highest。
//将当前线程(工作者线程)的优先级设置为 ThreadPriority.Highest。
Thread.CurrentThread.Priority = ThreadPriority.Highest;

es thread_pool esthreadpool 线程不够_es thread_pool_02


es thread_pool esthreadpool 线程不够_调优_09