首页 文章

有多少线程太多了? [关闭]

提问于
浏览
266

我正在编写一个服务器,当请求传入时,我将每个动作分支到一个线程中 . 我这样做是因为几乎每个请求都进行数据库查询 . 我正在使用线程池库来减少线程的构造/销毁 .

我的问题是 - 像这样的I / O线程有什么好的截止点?我知道这只是一个粗略的估计,但我们是在说几百个?成千上万的?


编辑:

谢谢大家的回复,似乎我只是要测试它以找出我的线程数上限 . 问题是:我怎么知道我达到了这个上限?究竟应该测量什么?

12 回答

  • 16

    有些人会说两个线程太多 - 我不是那个阵营:-)

    这是我的建议:衡量,不要猜测 . 一个建议是使其可配置并最初将其设置为100,然后将软件发布到野外并监控发生的情况 .

    如果你的线程使用率达到3,那么100就太多了 . 如果它在一天中的大部分时间保持在100,那么将其提高到200,看看会发生什么 .

    您实际上可以让您的代码本身监视使用情况并在下次启动时调整配置,但这可能是过度的 .


    澄清和阐述:

    我不是主张滚动你自己的线程池子系统,一定要使用你拥有的那个 . 但是,既然你问的是线程的一个很好的截止点,我假设你的线程池实现能够限制创建的最大线程数(这是一件好事) .

    我编写了线程和数据库连接池代码,它们具有以下功能(我认为这对性能至关重要):

    • 最小活动线程数 .

    • 最大线程数 .

    • 关闭一段时间未使用的线程 .

    第一个根据线程池客户端设置最低性能的基线(此线程数始终可用) . 第二个设置了活动线程对资源使用的限制 . 第三个会在安静时间返回基线,以最大限度地减少资源使用 .

    您需要 balancer 具有未使用线程(A)的资源使用与没有足够线程来执行工作的资源使用(B) .

    (A)通常是内存使用(堆栈等),因为不执行任何工作的线程将不会使用大量的CPU . (B)通常会在请求处理时延迟处理请求,因为您需要等待线程可用 .

    这就是你测量的原因 . 正如您所述,绝大多数线程将等待数据库的响应,因此它们将不会运行 . 有两个因素会影响您应该允许的线程数 .

    第一个是可用的DB连接数 . 这可能是一个硬限制,除非您可以在DBMS上增加它 - 我将假设您的DBMS在这种情况下可以采用无限数量的连接(尽管您理想情况下也应该测量它) .

    然后,您应该拥有的线程数取决于您的历史用途 . 你应该运行的最小值是你运行A%的最小数量,绝对最小值(例如,并使其像A一样可配置)5 .

    最大线程数应为历史最大B% .

    您还应该监视行为更改 . 如果由于某种原因,您的使用时间达到可用时间的100%(这会影响客户的性能),您应该提高允许的最大值,直到它再次高出B% .


    回答"what exactly should I measure?"问题:

    您应该具体衡量的是在负载下并发使用的最大线程数(例如,等待从DB调用返回) . 然后添加一个10%的安全系数(强调,因为其他海报似乎把我的例子作为固定的建议) .

    此外,这应该在 生产环境 环境中进行调整 . 可以事先得到一个估计,但你永远不知道什么样的产品会引发你的方式(这就是为什么所有这些东西都应该在运行时配置) . 这是为了捕捉到一些情况,例如客户来电的意外加倍 .

  • 30

    这个问题已经过彻底讨论,我没有机会阅读所有回复 . 但是,在查看同步线程数量的上限时,需要考虑以下几点在特定的系统中可以和平共处 .

    • 线程堆栈大小:在Linux中,默认线程堆栈大小为8MB(您可以使用ulimit -a来查找它) .

    • Max给定OS变体支持的最大虚拟内存 . Linux Kernel 2.4支持2 GB的内存地址空间 . 使用内核2.6,我有点大(3GB)

    • [1]显示每个给定Max VM Supported的最大线程数的计算 . 对于2.4,它结果是大约255个线程 . 2.6的数字有点大 .

    • 你有什么kindda内核调度程序 . 将Linux 2.4内核调度程序与2.6进行比较,后者为您提供O(1)调度,不依赖于系统中存在的任务数量,而第一个调度更多的是O(n) . 因此,内核调度的SMP功能也在系统中可持续线程的最大数量方面发挥了很好的作用 .

    现在,您可以调整堆栈大小以包含更多线程,但是您必须考虑线程管理(创建/销毁和调度)的开销 . 您可以对给定进程以及给定线程强制执行CPU关联,以将它们绑定到特定CPU,以避免CPU之间的线程迁移开销,并避免冷现金问题 .

    请注意,可以按照自己的意愿创建数千个线程,但是当Linux用完VM时,它只会随机开始查找进程(因此线程) . 这是为了防止实用程序配置文件被最大化 . (效用函数告诉系统范围的实用程序用于给定数量的资源 . 在这种情况下,CPU循环和内存中的常量资源,实用程序曲线随着越来越多的任务而变得平坦) .

    我确信Windows内核调度程序也可以做这种事情来处理资源的过度使用

    [1] http://adywicaksono.wordpress.com/2007/07/10/i-can-not-create-more-than-255-threads-on-linux-what-is-the-solutions/

  • 175

    如果您的线程正在执行任何类型的资源密集型工作(CPU /磁盘),那么您很少会看到超过一两个的好处,并且太多会很快消除性能 .

    “最佳情况”是您的后续线程将在第一个线程完成时停止,或者某些线程将在具有低争用的资源上具有低开销块 . 最糟糕的情况是,你开始颠倒缓存/磁盘/网络,你的整体吞吐量会下降 .

    一个好的解决方案是将请求放在池中,然后从线程池调度到工作线程(是的,避免连续的线程创建/销毁是一个很好的第一步) .

    然后,可以根据概要分析的结果,运行的硬件以及计算机上可能发生的其他事情来调整和缩放此池中活动线程的数量 .

  • 7

    你应该记住的一件事是python(至少是基于C的版本)使用所谓的global interpreter lock,它可以对多核机器的性能产生巨大影响 .

    如果你真的需要最多的多线程python,你可能想考虑使用Jython或其他东西 .

  • 2

    正如Pax正确地说, measure, don't guess . 这就是我为DNSwitness所做的,结果令人惊讶:理想的线程数远远高于我的想象,就像15,000个线程一样,以获得最快的结果 .

    当然,这取决于很多事情,这就是你必须衡量自己的原因 .

    Combien de fils d'exécution ?中的完整措施(仅限法语) .

  • 2

    我写了很多重度多线程的应用程序 . 我通常允许配置文件指定潜在线程的数量 . 当我针对特定客户进行调整时,我已将数字设置得足够高,以至于我对所有CPU内核的利用率都相当高,但不是很高,以至于我遇到内存问题(这些是32位操作系统)时间) .

    换句话说,一旦达到一些瓶颈,无论是CPU,数据库吞吐量,磁盘吞吐量等,添加更多线程都不会提高整体性能 . 但是直到你达到这一点,添加更多线程!

    请注意,这假设有问题的系统专用于您的应用,并且您不必非常好地(避免挨饿)其他应用 .

  • 9

    “大铁”答案通常是每个有限资源一个线程 - 处理器(CPU绑定),arm(I / O绑定)等 - 但这只有在您可以将工作路由到资源的正确线程时才有效被访问 .

    如果不可能,请考虑您拥有可替代资源(CPU)和不可替代的资源(武器) . 对于CPU来说,将每个线程分配给特定的CPU并不重要(尽管它有助于缓存管理),但对于武器,如果你不能给手臂分配一个线程,你会进入排队理论以及保持手臂忙碌的最佳数量 . 一般来说,我认为如果你不能根据所使用的手臂路由请求,那么每个手臂有2-3个线程将是正确的 .

    当传递给线程的工作单元没有执行合理的原子工作单元时,会出现复杂问题 . 例如,您可以让线程在一个点上访问磁盘,在另一个点上等待网络 . 这增加了额外线程可以进入并执行有用工作的“裂缝”的数量,但它也增加了额外线程污染彼此的缓存等的机会,并使系统陷入困境 .

    当然,你必须权衡所有这一点与线程的“重量” . 不幸的是,大多数系统都有非常重量级的线程(他们称之为“轻量级线程”通常根本就不是线程),所以最好在低端错误 .

    我在实践中看到的是,非常微妙的差异可以在多少线程最优化方面产生巨大差异 . 特别是,缓存问题和锁定冲突会极大地限制实际并发性 .

  • 1

    需要考虑的一件事是机器上将存在多少个将执行代码的核心 . 这代表了在任何给定时间可以进行多少线程的硬性限制 . 但是,如果在某些情况下,线程需要经常等待数据库执行查询,那么您可能希望根据数据库可以处理的并发查询数来调整线程 .

  • -10

    我认为这对你的问题有点躲闪,但为什么不把它们分成流程呢?我对网络的理解(从昔日的朦胧日子开始,我根本就没有真正的网络编码)是每个传入的连接可以作为一个单独的过程处理,因为如果有人在你的过程中做了一些讨厌的事情,它就不会核对整个计划 .

  • -6

    ryeguy,我目前正在开发一个类似的应用程序,我的线程数设置为15.不幸的是,如果我将其增加到20,它就会崩溃 . 所以,是的,我认为处理此问题的最佳方法是衡量当前配置是否允许多于或少于X个线程 .

  • 3

    在大多数情况下,您应该允许线程池来处理这个问题 . 如果您发布一些代码或提供更多详细信息,可能更容易看出是否有某些原因线程池的默认行为不是最好的 .

    您可以在此处找到有关此方法的更多信息:http://en.wikipedia.org/wiki/Thread_pool_pattern

  • 4

    与CPU核心一样多的线程是我经常听到的 .

相关问题