代码之家  ›  专栏  ›  技术社区  ›  Mark Ingram

线程与线程池

  •  128
  • Mark Ingram  · 技术社区  · 16 年前

    使用新线程和使用线程池中的线程有什么区别?有哪些性能优势?为什么我应该考虑使用池中的线程而不是我显式创建的线程?我在这里特别考虑.NET,但是一般的例子是可以的。

    10 回复  |  直到 6 年前
        1
  •  103
  •   community wiki 6 revs, 2 users 96% Karg    16 年前

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

    • 重用已经创建的线程,而不是创建新的线程(代价高昂的进程)
    • 当对新工作项的请求爆发时,限制线程创建的速度(我相信这仅在.NET 3.5中)

      • 如果您将100个线程池任务排队,那么它将只使用已经创建的线程来服务这些请求(比如说10个)。线程池将进行频繁的检查(我相信在3.5sp1中每500ms检查一次),如果有排队的任务,它将生成一个新的线程。如果您的任务很快,那么新线程的数量将很小,重新使用10个左右的线程执行短任务将比前面创建100个线程快。

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

      • 检查 Here 有关线程池如何在引擎盖下工作的详细信息

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

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

        2
  •  14
  •   Martin    16 年前

    .NET管理的线程池:

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

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

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

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

        3
  •  8
  •   Krzysztof    16 年前

    new Thread().Start()

    生成前台线程,如果关闭程序,这些线程将不会死亡。 线程池线程是在关闭应用程序时死亡的后台线程。

        4
  •  6
  •   PeterM    9 年前

    我很好奇这些电脑的相对资源使用情况,并在我的2012双核Inteli5笔记本电脑上运行了一个基准测试,它使用的是基于Windows8的.NET 4.0版本。线程池平均启动时间为0.035毫秒,其中线程平均启动时间为5.06毫秒。换句话说,对于大量的短寿命线程,池中的线程启动速度大约快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

        5
  •  3
  •   Community CDub    8 年前

    请在此处检查早期线程:

    When should I not use the ThreadPool in .Net?

    总结是,如果需要生成许多短时间线程,那么threadpool是很好的,而使用threads可以提供更多的控制。

        6
  •  1
  •   MSalters    16 年前

    对于线程池,线程本地存储不是一个好主意。它给线程一个“标识”;并不是所有线程都是相等的。现在,如果您只需要一组相同的线程,就可以在不增加创建开销的情况下完成工作,那么线程池尤其有用。

        7
  •  1
  •   Rob Prouse    16 年前

    如果您需要大量线程,那么可能需要使用线程池。它们重用线程,从而节省了线程创建的开销。

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

        8
  •  1
  •   supercat    10 年前

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

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

    如果一个方法在开始执行时不能在100毫秒左右退出,那么该方法应该通过除主线程池之外的其他方法执行。如果要执行的任务很多,CPU密集型但不会阻塞,那么使用应用程序线程池(每个CPU核心一个)来调度它们可能会很有帮助,因为在运行非阻塞CPU密集型任务时,使用比核心更多的线程会适得其反。但是,如果一个方法需要一秒钟或更长的时间来执行,并且将花费它的大部分时间来阻塞,那么该方法应该很可能在一个专用线程中运行,并且几乎肯定不应该在主线程池线程中运行。如果长时间运行的操作需要由I/O回调之类的东西触发,那么应该在回调之前为长时间运行的操作启动一个线程,并让它在回调脉冲的监视器上等待,或者让回调在回调退出时启动一个新线程来执行该操作,从而有效地返回把自己的线接到螺纹工具上。

        9
  •  0
  •   Robin    16 年前

    通常(我从未使用过.NET),线程池将用于资源管理目的。它允许在软件中配置约束。这也可能是出于性能的原因,因为创建新线程的成本可能很高。

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

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

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

        10
  •  0
  •   Marco Guignard    11 年前

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

    使用线程更新列表控件positionChanged事件(避免freez)上数据库中的某些字段时,表单出现问题。我的用户花了5分钟从数据库中出错(与Access的连接太多),因为他更改列表位置的速度太快…

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