好的,我们假设我们有一个带有"类型的线程池"动态扁平容器,最大容量为x,因为内存在堆栈上以提高性能。
用最少的代码(我不想具体说明):
template <int32 QSIZE, int32 PSIZE> class ThreadPool
{
public:
ThreadPool()
{
for (int32 i = 0; PSIZE > i; ++i)
{
m_Workers.push(Thread(thread_main, m_Queue, m_Signal, m_IsRunning));
}
}
~ThreadPool()
{
//Wait and destroy all threads
}
void run(Task task)
{
m_Queue.push(task);
m_Signal.wake_all();
}
private:
FlatVector<Thread, PSIZE> m_Workers; //PSIZE --> max capacity
FlatQueue<Task, QSIZE> m_Queue; //QSIZE --> max capacity
ConditionVariable m_Signal;
AtomicBool m_IsRunning;
};
class Task
是具有绑定参数和移动语义的inplace函数的实现。
FlatVector
是一个向量,在堆栈上有内存,最大容量为PSIZE
(池大小)。
FlatQueue
与容量为QSIZE
(队列大小)的队列基本上是相同的构造
一个Task
的最大大小为512位。
在最坏的情况下,是否有一个好的经验法则:线程池任务队列应该增长多大? (如果可能的话,考虑到给定的例子,如果不可能的话,对常规线程池的猜测也很好。)
在大多数情况下,我的池运行8个线程,因为这是我的核心数,使用池的应用程序可以获得更高线程数的体面优势。 (这是一个简单的物理模拟)
将任务打包到任务包中是否是更好的方法(考虑到这个例子,它们不会一起超过512位。)或者我应该跳过不能计算的任务被放置在这个框架中并在下一个计算它们?然后,物理计算将计算2帧。
Usualy我选择的队列大小介于64到128个任务之间,这很好(至少是性能方面的)但实际上感觉同时在一个池中的128个任务对我来说有点太多而且我没有&#39 ; t想浪费这么多的记忆。
如果我将池设置为高负载,有时我会同时超过池中64个任务的限制。 (这就是为什么我决定首先增加游泳池大小。)
在我的池中添加一个512位任务(最坏情况)需要在我的系统上花费1,02到1,3 e(-7)秒的时间。
对&#34;常规&#34;做同样的事情。线程池和&#34;常规&#34;具有堆分配和移动语义的函数绑定需要介于1.8 - 2.3 e(-5)秒之间,这表明在这种情况下使用堆栈有一个真正的好处。
答案 0 :(得分:0)
该问题的一般答案:
对于在不等待其他资源的情况下持续运行的工作负载,逻辑上,最大线程数应与物理处理器数相同(或者如果处理器具有超线程,则为两倍)。
对于等待其他资源的工作负载(例如,等待套接字连接),您需要通过拥有比逻辑处理器更多的线程(取决于您的等待时间)来补偿此延迟以获得最大吞吐量。如果大多数被阻止,数百个线程就可以了。您可以考虑分离任务的延迟限制部分和任务的CPU密集部分,以完全负载平衡每个具有不同线程数的工作负载。
假设您想要最大化吞吐量,您可以凭经验确定最佳线程数。
使用控制理论可以实现软件自调整线程数的有趣解决方案。 Philipp K. Janert的“计算机系统反馈控制”一书对此有很好的借鉴意义。
答案 1 :(得分:0)
在最坏的情况下,是否有一个好的经验法则:线程池任务队列应该增长多少?
我认为要问的正确问题是: