线程与ThreadPool

时间:2008-10-23 14:41:52

标签: .net multithreading architecture threadpool

使用新线程和使用线程池中的线程有什么区别?有什么性能优势,为什么我应该考虑使用池中的线程而不是我明确创建的线程?我在这里专门讨论.NET,但一般的例子很好。

11 个答案:

答案 0 :(得分:105)

线程池将为频繁和相对较短的操作带来好处

  • 重用已经创建的线程而不是创建新线程(一个昂贵的过程)
  • 当有新的工作项请求时,限制了线程创建的速度(我相信这只是在.NET 3.5中)

    • 如果排队100个线程池任务,它将只使用已经创建的线程来为这些请求提供服务(例如10个)。线程池将进行频繁检查(我相信3.5 SP1中每500ms),如果有排队任务,它将创建一个新线程。如果您的任务很快,那么新线程的数量将会很少,并且重新使用10个左右的线程来完成短任务将比预先创建100个线程更快。

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

    • 检查Here以获取有关线程池如何在引擎盖下运行的更深入信息

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

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

答案 1 :(得分:14)

.NET托管的线程池: -

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

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

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

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

答案 2 :(得分:8)

  

new Thread().Start()

生成Foreground线程,如果关闭程序,它将不会死亡。 ThreadPool线程是在关闭应用程序时死亡的后台线程。

答案 3 :(得分:7)

我对这些的相对资源使用感到好奇,并在我的2012双核英特尔i5笔记本电脑上使用.net 4.0发布版本在Windows 8上运行基准测试。线程池平均花费0.035毫秒开始平均5.06ms。换句话说,对于大量短期线程,池中的线程开始快了大约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

答案 4 :(得分:3)

点击此处查看之前的帖子:

When should I not use the ThreadPool in .Net?

总结一下,如果你需要产生许多短的线程,那么Threadpool是好的,而使用Threads可以让你获得更多的控制。

答案 5 :(得分:1)

使用线程池线程本地存储不是一个好主意。它给线程一个“身份”;并非所有线程都相等。现在线程池特别有用,如果你只需要一堆相同的线程,准备好在没有创建开销的情况下完成你的工作。

答案 6 :(得分:1)

如果你需要很多线程,你可能想要使用ThreadPool。它们重用线程,为您节省线程创建的开销。

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

答案 7 :(得分:1)

对于theadpool线程的主要需求是处理预计几乎立即完成的短任务。硬件中断处理程序通常在堆栈上下文中运行,这不适用于非内核代码,但硬件中断处理程序可能会发现应尽快运行用户模式I / O完成回调。为了运行这样的事情而创建一个新线程将是一个巨大的过度杀伤力。有一些预先创建的线程可以调度以运行I / O完成回调或其他类似的东西效率更高。

此类线程的一个关键方面是,如果I / O完成方法总是基本上立即完成而且从不阻塞,并且当前运行此类方法的此类线程的数量至少等于处理器的数量,唯一的方法任何其他线程可以在上述方法之一完成之前运行,如果其他方法块之一或其执行时间超过正常线程时间片;如果线程池按预期使用,那么这些都不会经常发生。

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

答案 8 :(得分:0)

一般情况下(我从未使用过.NET),线程池将用于资源管理。它允许将约束配置到您的软件中。它也可能出于性能原因而完成,因为创建新线程可能成本很高。

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

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

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

答案 9 :(得分:0)

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

使用线程来替换列表控件的positionchanged事件上的数据库中的某些字段时出现问题(避免使用freez)。我的用户花了5分钟从数据库中获取错误(与Access连接太多)因为他正在更快地更改列表位置......

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

答案 10 :(得分:0)

线程

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

线程池

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