一个好的线程池队列大小
A good thread pool queue size
好吧,让我们假设我们有一个带有"类型"动态平坦容器的线程池,该容器的最大容量为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
是具有绑定参数并移动语义的内置函数的实现。
FlatVector
是一个向量,堆栈上有内存,最大容量为PSIZE
(池尺寸(。
FlatQueue
基本上是与QSIZE
(队列大小(
一个Task
的最大尺寸为512位。
在最坏的情况下,有良好的经验法则是线程池任务队列应该长大的?(如果可能的话,考虑到给定的示例,如果不可能,请在常规线程池上猜测也可以。(
在大多数情况下,我的池在8个线程中运行,因为这是我的核心计数,而使用池的应用程序可以利用更高的线程计数。(这是一个简单的物理模拟(
考虑到这个示例,这是将任务一起包装到任务捆绑包中的更好方法(只要它们不会超过512位。框架不再在下一个中计算它们?然后,将计算2帧的物理计算。
通常,我选择了一个队列大小的64-128个任务(至少明智的表现(,但实际上感觉就像在一个池中的128个任务对我来说有点多想要浪费这一数量的记忆。
有时,如果我在高负载下设置池,我同时超出了池中64个任务的限制。(这就是为什么我决定首先增加泳池大小的原因。(
在我的池中添加一个512位任务(最坏的情况(在我的系统上需要1,02和1,3 E功率(-7(秒。
使用"常规"线程池和具有堆分配和移动语义的"常规"线程池和"常规"功能绑定在1.8-2.3 e功率(-5(秒之间,这表明使用堆栈有真正的好处在这种情况下。
对问题的一般答案:
对于不再等待其他资源而不断运行的工作负载,从逻辑上讲,最大线程的数量应与物理处理器的数量相同(或者如果处理器具有超线程(。
对于等待其他资源的工作负载(例如,等待套接字连接(,您将需要补偿此延迟以获得最大吞吐量,通过拥有比逻辑处理器更多的线程(取决于您的等待时间(。如果大多数被阻止,数百个线程将很好。您可以考虑将任务的延迟限制部分和任务的CPU密集部分分开,以充分加载平衡工作负载,每个工作负载每个都有不同的线程计数。
假设您想最大化吞吐量,您可以从经验上确定最佳螺纹计数。
使用控制理论可以实现软件自我调整线程计数的有趣解决方案。Philipp K. Janert的《计算机系统的反馈控制》是一个很好的参考。
有一个好的经验法则,在最坏情况下,线程池任务队列应长多少?
我认为要问的正确问题是:
- 任务可以等待多长时间才能进行评估?
- 特定类型的新任务是否将现有任务取代?
- 为什么我的多线程作业队列崩溃
- 在c++队列中使用pop和visit实现线程安全
- 共享队列的线程安全
- 线程安全队列 c++
- 将项目添加到队列时运行线程
- 线程安全的引用计数队列C++
- 对C++中的队列进行多线程访问
- asio::io_service 具有多个线程的优先级队列处理
- C++11如何在1个线程中使用条件变量处理2个线程安全队列
- QtThread:I/O 队列的工作线程
- 如何做 gtkmm 线程安全队列绘制?
- 线程安全队列出现分段错误
- 一个好的线程池队列大小
- 从调度队列块 [ swift / c++ ] 创建线程
- Qt的事件循环线程是安全的还是原子的?处理"队列连接"时如何同步?
- IPC Unix 消息队列线程安全吗?
- 在多线程中使用LinkedList队列
- 工作线程队列的这种变体是某种模式或通用结构吗?
- 多线程队列原子操作
- 如何进行多线程队列处理