要创建多少个线程以及何时创建?

时间:2009-02-04 07:52:10

标签: c++ linux multithreading networking

我有一个网络Linux应用程序,它接收来自多个目的地的RTP流,进行非常简单的数据包修改,然后将流转发到最终目的地。

如何确定处理数据所需的线程数?我想,我无法为每个RTP流打开一个线程,因为可能有数千个。我应该考虑CPU核心的数量吗?还有什么重要的? 感谢。

7 个答案:

答案 0 :(得分:22)

了解在服务器上使用多个线程的目的很重要;服务器中的许多线程用于减少latency而不是提高速度。通过拥有更多线程,您不会使cpu更快,但是您更有可能在给定时间段内始终出现一个线程来处理请求。

拥有一堆只是并行移动数据的线程是一个相当低效的射击枪(每个请求创建一个线程自然就完全失败了)。使用thread pool模式可以是一种更有效,更集中的方法来减少延迟。

现在,在线程池中,您希望拥有至少与CPU /核心一样多的线程。你可以拥有更多,但额外的线程将再次只减少延迟而不是提高速度。

将组织服务器线程的问题视为类似于在超市中组织一条线路。您想让很多收银员工作得更慢,还是一位收银员工作超快?快速收银员的问题不在于速度,而是一个拥有大量杂货的顾客可能仍会占用大量的时间。对许多线程的需求来自于一些请求会占用大量时间并阻塞所有线程的可能性。通过这种推理,您是否从许多较慢的收银员中受益取决于您是否拥有相同数量的杂货还是截然不同的数字。回到基本模型,这意味着您必须使用您的线程编号来确定在给定流量的特定特征时最佳情况,并查看处理每个请求所花费的时间。

答案 1 :(得分:10)

合理线程的数量通常取决于执行单元的数量,IO与计算的比率和可用内存。

执行单位数(XU

计算可以同时激活多少个线程。根据您的计算可能会或可能不会计算超线程等内容 - 混合指令工作负载更好。

IO与计算的比率(%IO

如果线程从不等待IO但总是计算(%IO = 0),则使用比XU更多的线程只会增加内存压力和上下文切换的开销。如果线程总是等待IO并且从不计算(%IO = 1),则使用poll()select()的变体可能是个好主意。

对于所有其他情况,XU / %IO给出了完全使用可用XU所需的线程数的近似值。

可用内存(Mem

这更像是一个上限。每个线程使用一定量的系统资源(MemUse)。 Mem / MemUse为您提供系统可支持的线程数的近似值。

其他因素

即使您可以猜测或(更好地)测量上述数字,整个系统的性能仍然会受到其他因素的限制。例如,可能在系统上运行另一个服务,该服务使用一些XU和内存。另一个问题是一般可用的IO带宽(IOCap)。如果每个传输的字节所需的计算资源少于您提供的XU,那么显然您需要更少关注完全使用它们以及更多关于提高IO吞吐量的信息。

有关后一问题的更多信息,请参阅此Google Talk about the Roofline Model

答案 2 :(得分:4)

我会说,尝试只使用一个线程;它使编程更容易。虽然你需要使用像libevent这样的东西来复用连接,但你不会遇到任何意外的同步问题。

一旦你有了一个有效的单线程实现,你就可以进行性能测试,并决定是否需要多线程实现。

即使需要多线程实现,也可能更容易将其分解为多个进程而不是线程(即不共享地址空间; fork()或执行来自父进程的多个进程副本)如果他们不'有很多共享数据。

你也可以考虑使用类似Python的“Twisted”来简化实现(这就是它的设计)。

对于在进程中使用线程可能不是一个好例子 - 但是在你的情况下可能很难说。这取决于您需要在线程之间共享多少数据。

答案 3 :(得分:2)

我会查看此应用程序的线程池。

http://threadpool.sourceforge.net/

允许线程池管理您的线程和队列。

您可以稍后调整基于性能分析的最大和最小线程数。

答案 4 :(得分:2)

倾听建议您使用libevent(或OS特定实用程序,如epoll / kqueue)的人们。在许多连接的情况下,这是绝对必须的,因为像你说的那样,创建线程将是一个巨大的性能命中,而select()也不会完全削减它。

答案 5 :(得分:1)

让您的计划决定。添加代码来测量吞吐量并动态增加/减少线程数以最大化它。

这样,无论执行核心数量和其他因素如何,您的应用程序都将始终表现良好

答案 6 :(得分:0)

避免尝试为每个客户端请求创建一个(甚至N个)线程是个好主意。这种方法通常是不可扩展的,你肯定会遇到内存使用或上下文切换的问题。您应该查看使用线程池方法,并查看传入请求作为池中任何线程要处理的任务。然后,此方法的可伸缩性受池中理想线程数的限制 - 通常这与CPU核心数相关。您希望尝试让每个线程在单个核心上使用100%的CPU - 因此在理想情况下,每个核心将有1个线程,这将减少上下文切换到零。根据任务的性质,这可能是不可能的,也许线程必须等待外部数据,或从磁盘或其他任何内容读取,因此您可能会发现线程数增加了一些比例因子。