线程与线程池

使用新线程和使用线程池中的线程有什么区别?有哪些性能好处,为什么要考虑使用池中的线程而不是显式创建的线程?我特别想到的是。NET 在这里,但一般的例子是好的。

82991 次浏览

对于线程池,线程本地存储不是一个好主意。它为线程提供了一个“标识”; 不再是所有线程都是相等的。现在,如果您只需要一堆相同的线程,就可以在没有创建开销的情况下完成工作,那么线程池就特别有用。

通过以下方法,线程池将为频繁和相对较短的操作提供好处

  • 重用已经创建的线程,而不是创建新线程(这是一个昂贵的过程)
  • 当出现对新工作项的大量请求时,控制线程创建的速度(我相信这只是在。净值3.5)
    • 如果您对100个线程池任务进行排队,那么它将只使用已经创建的线程来服务这些请求(例如10个)。线程池将进行频繁的检查(我相信在3.5 SP1中每500毫秒检查一次) ,如果有排队的任务,它将生成一个新线程。如果您的任务很快,那么新线程的数量就会很少,重用10个左右的线程执行短任务将比预先创建100个线程要快。

    • 如果您的工作负载始终有大量的线程池请求进入,那么线程池将通过上述进程在池中创建更多的线程来调整自身以适应您的工作负载,从而有更多的线程可用于处理请求

    • 检查 给你获得更多关于线程池如何在引擎盖下工作的深入信息

如果作业运行时间相对较长(可能大约一两秒钟,但这取决于具体情况) ,那么自己创建一个新线程会更合适

@ Krzysztof-线程池线程是在主线程结束时停止的后台线程。默认情况下,手工创建的线程是前台的(在主线程结束后将继续运行) ,但是可以在对它们调用 Start 之前将其设置为后台。

点击这里查看之前的帖子:

什么时候不应该使用.Net 中的 ThreadPool?

总的来说,如果需要产生许多短命线程,Threadpool 是一个很好的选择,而使用 Threads 可以提供更多的控制。

如果需要大量线程,可能需要使用 ThreadPool。它们重用线程,节省了线程创建的开销。

如果您只需要一个线程来完成一些事情,那么线程可能是最简单的。

还有

new Thread().Start()

如果您关闭程序,前台线程将不会死亡。 ThreadPool 线程是在关闭应用程序时死亡的后台线程。

一般来说(我从来没有用过。NET) ,线程池将用于资源管理目的。它允许将约束配置到您的软件中。这也可能是出于性能原因,因为创建新线程的成本可能很高。

也可能有系统特定的原因。在 Java 中(同样,我不知道这是否适用于。NET) ,线程管理器可以在每个线程从池中提取时应用特定于线程的变量,并在返回时取消设置它们(传递类似标识的常用方法)。

约束示例: 我只有10个 db 连接,所以我只允许10个工作线程访问数据库。

这并不意味着您不应该创建自己的线程,但是在一些条件下使用池是有意义的。

.NET 托管线程池:-

  • 根据当前工作负载和可用硬件调整自身大小
  • 包含工作线程 还有完成端口线程(专门用于服务 IO)
  • 为大量相对短命的操作进行了优化

其他线程池实现可能更适合长时间运行的操作。

具体来说,使用线程池来阻止应用程序创建 太多了线程。线程池最重要的特性是工作队列。也就是说,一旦您的计算机足够忙,线程池将对请求进行排队,而不是立即产生更多的线程。

因此,如果您将创建一个小的,有界的线程数量自己创建它们。如果您无法预先确定可以创建多少个线程(例如,它们是为响应传入的 IO 而创建的) ,并且它们的工作将是短期的,请使用线程池。如果您不知道有多少人,但是他们的工作将是长期运行的,那么平台中没有任何东西可以帮助您——但是您可以找到适合的替代线程池实现。

如果您不知道或无法控制将创建多少个线程,那么使用池是一个好主意。

只是在列表控件的 positionchanged事件中,表单使用线程来更新数据库中的某些字段时出现了问题(避免冻结)。我的用户花了5分钟才从数据库中得到一个错误(与 Access 的连接太多) ,因为他更改列表位置的速度太快..。

我知道还有其他方法可以解决基本问题(包括不使用访问权限) ,但是共享是一个很好的开始。

头池线程的主要需求是处理预期几乎立即完成的短小任务。硬件中断处理程序通常在堆栈环境中运行,这种环境不适合非内核代码,但是硬件 interrupt handler 可能会发现用户模式的 I/O 完成回调应该尽快运行。为了运行这样一个东西而创建一个新的线程将是巨大的过度杀伤。有一些预先创建的线程,可以分派它们来运行 I/O 完成回调或其他类似的事情,这样效率会高得多。

这种线程的一个关键方面是,如果 I/O 完成方法总是实质上瞬间完成并且从不阻塞,而且目前正在运行这种方法的线程的数量至少等于处理器的数量,那么在上述方法之一完成之前任何其他线程可以运行的唯一方法是,如果其他方法阻塞或其执行时间超过正常的线程时间片; 如果按照预期使用线程池,这两种情况都不应该经常发生。

如果一个方法在开始执行时不能在100ms 左右退出,那么应该通过主线程池以外的其他方式执行该方法。如果一个人有很多 CPU 密集型但不会阻塞的任务要执行,那么使用一个独立于“主”线程池的应用程序线程池(每个 CPU 核一个线程池)来分派它们可能是有帮助的,因为在运行非阻塞 CPU 密集型任务时,使用比核更多的线程会适得其反。但是,如果一个方法需要一秒或更长的时间来执行,并且大部分时间都被阻塞,那么该方法可能应该在一个专用线程中运行,而且几乎可以肯定不应该在一个 main-threadpool 线程中运行。如果一个长时间运行的操作需要被类似 I/O 回调这样的事情触发,那么应该在回调之前启动一个线程来执行这个长时间运行的操作,并让它在回调脉冲的监视器上等待,或者在回调退出时让回调启动一个新的线程来执行这个操作,有效地将自己的线程返回到线程池。

我对这些产品的相对资源使用情况感到好奇,并在我2012年使用的双核 Intel i5笔记本电脑上运行了一个基准测试。Net 4.0版本构建在 Windows 8上。线程池的平均启动时间为0.035 ms,而线程池的平均启动时间为5.06 ms。换句话说,对于大量的短寿命线程,线程池中的线程启动速度要快300倍。至少在测试范围(100-2000)的线程中,每个线程的总时间似乎相当稳定。

这是被基准测试的代码:

    for (int i = 0; i < ThreadCount; i++) {
Task.Run(() => { });
}


for (int i = 0; i < ThreadCount; i++) {
var t = new Thread(() => { });
t.Start();
}

enter image description here

线程 :

  1. 创建线程比使用线程池慢得多。
  2. 可以更改线程的优先级。
  3. 进程中与资源相关的最大线程数。
  4. 线程处于操作系统级别,由操作系统控制。
  5. 当任务相对较小时,使用 Thread 是一个更好的选择 长期的

线程池 :

  1. 在线程池上运行 Thread 比直接运行要快得多 创建一个线程。
  2. 基于。不能更改线程运行的优先级 线池。
  3. 每个进程只有一个线程池。
  4. 线程池由 CLR 管理。
  5. 线程池对于短期操作很有用。
  6. 线程池中的线程数与应用程序相关 装弹。
  7. TPL 任务基于线程池运行