多less个线程太多了?
我正在写一个服务器,当请求传入时,我将每个动作分支到一个线程中。 我这样做是因为几乎每个请求都会使数据库查询。 我正在使用一个线程库来减less线程的构造/销毁。
我的问题是,对于像这样的I / O线程来说,什么是一个好的切入点? 我知道这只是一个粗略的估计,但我们谈论数百? 成千上万的?
编辑:
谢谢大家的回复,看来我只是要testing一下,找出我的线程数上限。 问题是,我怎么知道我已经达到了天花板? 我究竟应该测量什么?
有人会说, 两个线程太多了 – 我不是在这个阵营:-)
这是我的build议: 措施,不要猜测。 一个build议是使其可configuration,并将其初始设置为100,然后将您的软件发布到野外并监视发生的情况。
如果你的线程使用高峰在3,那么100是太多了。 如果在一天中的大部分时间里都保持在100,那么将它提高到200,看看会发生什么。
你实际上可以让你的代码本身监视使用情况,并在下次启动时调整configuration,但这可能是矫枉过正的。
澄清和阐述:
我不主张使用自己的线程池子系统。 但是,因为您正在询问线程的一个好的切点,所以我假设您的线程池实现能够限制创build的最大线程数(这是一件好事)。
我编写了线程和数据库连接池代码,它们具有以下特性(我认为这对于性能非常重要):
- 最小数量的活动线程。
- 最大线程数。
- closures一段时间未使用的线程。
第一个设置线程池客户端的最低性能的基线(这个线程总是可用的)。 第二个设置活动线程对资源使用的限制。 第三个在安静的时间将您返回到基准线,以最大限度地减less资源使用。
您需要平衡具有未使用的线程(A)的资源使用情况与没有足够的线程来完成工作(B)的资源使用情况。
(一)通常是内存使用(堆栈等),因为一个不工作的线程将不会使用太多的CPU。 (B)通常会延迟处理请求,因为你需要等待一个线程变得可用。
这就是你测量的原因。 正如你所说的,绝大多数的线程将等待数据库的响应,所以它们不会运行。 有两个因素影响你应该允许多less个线程。
首先是可用的数据库连接数。 这可能是一个严格的限制,除非你可以在DBMS中增加它 – 我将假设你的DBMS在这种情况下可以采用无限数量的连接(尽pipe你最好也是在测量这个连接)。
那么,你应该有多less线程取决于你的历史使用。 你应该运行的最小数量是你运行的最小数量+ A%,绝对最小值(例如,可以像A一样configuration)5。
最大线程数应该是你的历史最大值+ B%。
你也应该监视行为的变化。 如果由于某种原因,您的使用率达到可用时间的100%(这样会影响客户的performance),您应该提高最高允许值,直到再次提高B%为止。
为了回应“我究竟应该测量什么?” 题:
你应该特别测量的是在负载下并发使用的最大线程数量(例如,等待从DB调用返回)。 然后增加一个10%的安全系数(强调,因为其他海报似乎把我的例子作为固定的build议)。
另外,这应该在生产环境中进行调整。 预先得到估计值是可以的,但是你永远不知道什么时候会产生什么产量(这就是为什么所有这些东西都应该在运行时可configuration的原因)。 这是为了赶上一个情况,例如客户来电的意外翻倍。
这个问题已经被彻底的讨论过了,我没有机会读到所有的答案。 但是在考虑可以在给定系统中和平共处的并发线程的数量的上限的时候,几乎没有什么要考虑的。
- 线程堆栈大小:在Linux中,默认线程堆栈大小为8MB(可以使用ulimit -a来查找)。
- 指定操作系统版本支持的最大虚拟内存。 Linux Kernel 2.4支持2 GB的内存地址空间。 与内核2.6,我有点大(3GB)
- [1]显示了每个给定的最大VM支持的最大线程数的计算。 对于2.4,它变成了大约255个线程。 对于2.6这个数字有点大。
- 你有什么kindda内核调度程序。 比较Linux 2.4内核调度程序和2.6,后者给你一个O(1)调度,不依赖于系统中存在的任务数量,而第一个是更多的O(n)。 所以内核调度的SMP能力也对系统中可持续线程的最大数量起到很好的作用。
现在,您可以调整堆栈大小以包含更multithreading,但是必须考虑线程pipe理(创build/销毁和调度)的开销。 您可以对给定的进程以及给定的线程强制执行CPU亲和性,以将其与特定的CPU绑定,以避免CPU之间的线程迁移开销,并避免冷现金问题。
请注意,可以根据自己的意愿创build数千个线程,但是当Linux耗尽虚拟机时,它只是随机地开始查杀进程(即线程)。 这是为了保持实用程序configuration文件不被占用。 (效用函数告诉系统对于给定数量的资源的实用程序。在这种情况下,CPU周期和内存中的资源不变,实用程序曲线变平坦,任务数量越来越多)。
我确信Windows内核调度程序也可以处理这种资源的利用
如果您的线程正在执行任何types的资源密集型工作(CPU /磁盘),那么您将很less看到超过一个或两个的好处,并且太多将会非常快速地杀死性能。
“最好的情况”是你的后面的线程会在第一个线程完成的时候停顿,或者有些线程在低争用的资源上会有低开销块。 最糟糕的情况是,你开始颠簸caching/磁盘/networking,整体吞吐量下降。
一个好的解决scheme是把请求放在一个池中,然后从一个线程池分派给工作线程(是的,避免连续的线程创build/销毁是一个很好的第一步)。
然后可以根据分析的结果,正在运行的硬件以及机器上可能发生的其他事情来调整和调整此池中活动线程的数量。
有一点你应该记住的是,python(至less是基于C的版本)使用所谓的全局解释器锁 ,这对多核机器的性能有很大的影响。
如果你真的需要multithreadingpython,你可能会考虑使用Jython或其他东西。
正如Pax正确地说, 措施,不要猜测 。 那我所做的对于DNSwitness和结果是惊讶的:理想的线程数量比我想象的要高得多,像15000个线程得到最快的结果。
当然,这取决于很多事情,这就是为什么你必须衡量自己。
Combien de fils d'exécution的完整措施(法文版) ? 。
我认为这对你的问题有点闪避,但是为什么不把它们分解成stream程呢? 我对networking的理解(从过去的朦胧时代开始,我根本就没有真正编码networking)是每个传入的连接都可以作为一个单独的过程来处理,因为如果有人在你的过程中做了一些令人讨厌的事情,核整整个程序。
我已经写了大量的multithreading应用程序。 我通常允许一个configuration文件指定潜在线程的数量。 当我调整了特定的客户,我已经设置了足够高的数字,我所有的CPU核心的利用率是相当高的,但不是很高,我遇到了内存问题(这些是32位操作系统时间)。
换句话说,一旦遇到CPU,数据库吞吐量,磁盘吞吐量等瓶颈,增加更多的线程不会增加整体性能。 但是,直到你达到这一点,添加更多的线程!
请注意,这里假定有问题的系统专用于您的应用程序,并且您不必很好地玩(避免挨饿)其他应用程序。
“大铁”的答案通常是每个有限的资源处理器(CPU绑定),arm(I / O绑定)等一个线程 – 但只有当您可以将工作路由到正确的线程资源被访问。
如果这是不可能的,考虑你有可替代的资源(CPU)和不可替代的资源(武器)。 对于CPU来说,将每个线程分配给特定的CPU并不重要(尽pipe它有助于cachingpipe理),但是对于武器,如果不能将线程分配给arm,则可以进入排队理论,以及保持武器的最佳数量忙。 一般来说,我认为,如果你不能根据使用的arm路由请求,那么每个arm有2-3个线程将是正确的。
当传递给线程的工作单元没有执行合理的primefaces工作单元时,就会出现复杂情况。 例如,你可能有线程在一点访问磁盘,另一点在networking上等待。 这增加了额外的线程可以进入并做有用的工作的“裂缝”的数量,但是这也增加了额外的线程污染对方的caching等的机会,并使系统陷入沉没。
当然,你必须权衡这一切与线程的“重量”。 不幸的是,大多数系统都有非常重的线程(他们称之为“轻量级线程”通常不是线程),所以最好在错误的方面犯错。
我在实践中看到的是,非常微妙的差异可以使多less线程达到最佳状态的巨大差异。 特别是,caching问题和locking冲突可以大大限制实际并发的数量。
有一点需要考虑的是机器上有多less个内核会执行代码。 这代表了在任何给定时间可以进行多less个线程的严格限制。 但是,如果像你的情况一样,线程需要经常等待数据库执行一个查询,那么你可能希望根据数据库可以处理多less个并发查询来调整你的线程。
ryeguy,我目前正在开发一个类似的应用程序,我的线程数被设置为15.不幸的是,如果我增加它在20,它崩溃。 所以,是的,我认为处理这个问题的最好方法是衡量你当前的configuration是否允许多于或less于X个线程。
在大多数情况下,你应该允许线程池来处理这个问题。 如果你发布一些代码或者提供更多的细节,可能会更容易看出是否有某种原因,线程池的默认行为不是最好的。
你可以在这里find更多关于这应该如何工作的信息: http : //en.wikipedia.org/wiki/Thread_pool_pattern
和CPU核心一样多的线程是我经常听到的。