【问题标题】:A good thread pool queue size一个好的线程池队列大小
【发布时间】:2017-11-08 16:38:25
【问题描述】:

好的,假设我们有一个带有“某种”动态扁平容器的线程池,它的最大容量为 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 power(-7) 秒。

对“常规”线程池和具有堆分配和移动语义的“常规”函数绑定执行相同操作需要 1.8 - 2.3 e power(-5) 秒之间的时间,这表明使用堆栈确实有​​好处在这种情况下。

【问题讨论】:

  • 编写自己的线程池类很像编写自己的字符串类。也许你一生中至少做一次这件事有点重要,但将你所做的与其他程序员所做的进行比较同样重要。只有那个才能提供洞察力。当你这样做时,你最终会消除 PSIZE,因为它的最佳值是一个运行时细节,它取决于你的代码运行的特定机器。而且您也很可能会消除 QSIZE,因为没有像样的方法来预先猜测值并处理超出该限制的情况。比较一下,很重要。
  • 公平点,我知道一个池(通常)应该有一个 cpu 核心的大小。稍后,至少线程数将在运行时用 getCoreCount() 函数替换(这就是你正确的地方)。尽管如此,带有 QSIZE 的堆栈容器仍将保留,因为堆栈容器的性能优势非常强大。实际上,我已经在以一种我不太喜欢的方式处理溢出:如果队列已满,我会在主线程上执行它们。这是我想在未来避免的事情,这就是为什么我正在寻找一个运行更并行的更好的解决方案。

标签: c++ multithreading threadpool


【解决方案1】:

有没有一个好的经验法则,在最坏的情况下线程池任务队列应该增长到多大?

我认为要问的正确问题是:

  • 任务在被评估之前可以等待多长时间?
  • 特定类型的新任务会取代现有任务吗?

【讨论】:

    【解决方案2】:

    问题的一般答案:

    对于在不等待其他资源的情况下持续运行的工作负载,从逻辑上讲,最大线程数应与物理处理器数相同(如果处理器具有超线程,则为两倍)。

    对于等待其他资源的工作负载(例如等待套接字连接),您需要通过拥有比逻辑处理器更多的线程(取决于您的等待时间)来补偿这种延迟以获得最大吞吐量。如果大多数线程被阻塞,数百个线程会很好。您可以考虑将任务的延迟受限部分和任务的 CPU 密集部分分开,以完全负载平衡每个具有不同线程数的工作负载。

    假设您想要最大化吞吐量,您可以凭经验确定最佳线程数。

    使用控制理论可以实现软件自调整线程数的有趣解决方案。 Philipp K. Janert 所著的《计算机系统反馈控制》一书是这方面的一个很好的参考。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-05
      • 1970-01-01
      • 1970-01-01
      • 2011-03-25
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多