【问题标题】:Maximizing Worker Thread Utilization最大化工作线程利用率
【发布时间】:2010-08-06 01:44:24
【问题描述】:

为了解决一个问题(以及更好地理解多任务处理),我编写了一个小型线程池实现。这个线程池启动了一些工作线程,当线程池的客户端添加任务时,这些线程会从队列中弹出任务。就这个问题而言,当任务队列为空时,工作线程全部终止。

在进行了一些基本的基准测试之后,我发现应用程序花费了大约 60% 的时间来等待获取队列锁。大概这主要发生在工作线程中。

这仅仅是表明我没有给工作线程足够的工作,还是更多?我可能缺少一些简单的方法来提高工作线程的吞吐量吗?

编辑:这是一些粗略的伪代码,应该可以说明一些事情。这是在工作线程执行期间获取/释放锁的仅有的两个地方(这是应用程序运行时间的绝大部分)。

std::list<task_t> task_list;

// Called by the client to add tasks to the thread pool
void insert_task(const task_t& task)
{
    lock_type listlock(task_mutex);

    task_list.push_back(task);
}

// The base routine of each thread in the pool. Some details
// such as lifetime management have been omitted for clarity.
void worker_thread_base()
{
    while (true)
    {
        task_t task;

        {
        lock_type listlock(task_mutex);

        if (task_list.empty())
            continue;

        task = task_list.front();

        task_list.pop_front();
        }

        do_task(task);
    }
}

【问题讨论】:

  • 我们需要查看一些代码来了解为什么您的应用会卡在队列锁上。我认为你的线程应该大部分时间都停留在“等待”状态(使用条件变量或类似的东西)。

标签: multithreading optimization mutex threadpool worker-thread


【解决方案1】:

您的设计是建立在每个线程所在的位置并“旋转”试图获取锁的。这将不断发生,除非每个工作线程都在执行工作 - 在这种情况下,锁将不会被获取并且工作将会发生。

如果您的所有线程都处于锁定状态,并且在锁上旋转,您将使用相当多的 CPU 时间等待。考虑到您的设计,这在某种程度上是意料之中的。

您会发现,如果您的工作线程较少,阻塞的时间百分比可能会显着减少 - 当您拥有的工作项多于线程时,您将花费很少的时间等待该锁。

更好的设计是为您的工作队列使用某种形式的无锁队列,因为这可以防止此时等待。此外,拥有一个可以阻塞工作线程直到队列中有工作的等待句柄将防止不必要的旋转。

【讨论】:

    【解决方案2】:

    您是否尝试使用单个锁、多个锁来执行此操作?互斥体?您使用的是什么等待语义?

    我会从你的描述中猜测(这纯粹是猜测)你有类似的东西:

    lock(theLock) {
     // ... do lots of work ...
    }
    

    在您的主线程中,其中包含要分派到轻量级线程的代码。您可能会看到等待时间延长的一个原因是,您需要从已启动的线程返回信号,表明它们已排队等待执行(这也是一个猜测,因为您没有提供任何代码)。

    您可以解决此问题的一种方法是从使用显式锁(如上所述)切换到使用信号互斥锁,当您希望其中一个线程抢占工作时,该互斥锁会发出脉冲。

    虽然没有看到您当前的实现,但我不确定我是否可以超越这一点。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-12
      • 2017-12-28
      相关资源
      最近更新 更多