【问题标题】:TBB for a workload that keeps changing?TBB 是否适用于不断变化的工作负载?
【发布时间】:2012-05-14 23:50:58
【问题描述】:

很抱歉,我似乎没有得到intel's TBB,它看起来很棒且受支持,但我无法理解如何使用它,因为我想我不习惯从以下方面考虑并行性任务,而是将其视为线程。

我当前的工作负载有一个作业将工作发送到队列以继续处理(考虑递归,但不是调用自身,而是将工作发送到队列)。我在 Java 中进行这项工作的方式是创建一个并发队列(非阻塞队列)和线程池执行器,用于处理队列/将工作发送回它。但是现在我正在尝试在 C++ 中做类似的事情,我发现 TBB 可以创建池,但它的方法非常不同(Java 线程似乎只要它们在队列中工作就可以继续工作,但 TBB 似乎打破了任务开头)。

这是我所做的一个简单的 Java 示例(在此之前我设置了我想要的线程数等):

static class DoWork implements Callable<Void> {
    // queue with contexts to process
    private Queue<int> contexts;

    DoWork(Context request) {
        contexts = new ArrayDeque<int>();
        contexts.add(request);
    }

    public Void call() {
        while(!contexts.isEmpty()) {
            //do work 
            contexts.add(new int(data)); //if needs to be send back to the queue to do more work
        }
    }
}

我确定它可以在 TBB 中执行此操作,但我只是不确定如何,因为它似乎在我发送它时破坏了我的工作。因此,如果队列中有 2 个项目,它可能只会启动 2 个线程,但不会随着更多工作的进入而增长(即使我有 8 个内核)。

有人可以帮助我了解如何完成我的任务,还可以建议一种更好的方法来考虑来自使用 Java 线程环境的 TBB(我也不忠于 TBB,所以如果有更容易/更好的东西,那么我就是很高兴学习它。我只是不喜欢 c++ 线程池,因为它似乎没有积极开发)?

【问题讨论】:

  • Context 数据类型是什么?课程最初是DoWork&lt;Context&gt;吗?
  • @moshbear 为简单起见,我只是在示例中将其设为 int。当我真正这样做时,它是一个 int 和一个列表。抱歉应该在示例中将其转换为 int。
  • 这是您的代码的 STL 翻译:codepad.org/vs4S1UtB。你应该从那里去。
  • @moshbear 非常感谢。我真的很抱歉,我知道如何设置队列,我的问题更多是关于让线程使用池处理它,因为队列的大小是动态变化的..

标签: c++ multithreading tbb


【解决方案1】:

基于并行处理的项目队列的方法,其中每个线程只从队列中弹出一个项目并继续(并可能在某个时候将新项目添加到队列的末尾)从根本上是错误的,因为它限制了应用程序的并行性。队列成为单点同步,线程需要等待才能访问下一个要处理的项目。在实践中,当任务(每个项目的处理作业)非常大并且需要不同的时间来完成时,这种方法有效,与(大多数)线程同时完成并进入队列时相比,允许队列较少竞争以便他们处理下一个项目。

如果您正在编写一段可重用的代码,则无法保证任务足够大或大小不同(执行时间)。

我假设您的应用程序可扩展,这意味着您从队列中的大量项目(远大于线程数)开始,而当线程进行处理时,它们会在末尾添加足够的任务,因此在申请完成之前为每个人提供足够的工作。

如果是这种情况,我宁愿建议您保留项目的两个线程安全向量(例如 TBB 的 concurrent_vectors)以实现互换性。您从一个向量(您的初始项目集)开始,然后 enque() 一个任务(我认为它在 TBB 参考手册的第 12 章中的某处进行了描述),它在项目的初始向量上执行 parallel_for。在处理第一批时,您会将新项目 push_back 到第二个 concurrent_vector 上,当您完成第一个时,您 enque() 在第二个向量上使用 parallel_for 的任务并开始将新项目推回第一个.您可以尝试更好地重叠项目的并行处理,方法是使用三个向量而不是两个向量,并在它们之间逐渐移动,同时仍有足够的工作让所有线程保持忙碌。

【讨论】:

    【解决方案2】:

    您正在尝试做的正是 TBB 的 parallel_do 的设计目标。 parallel_do 调用的“body”传递了一个“feeder”参数,您可以在处理任务时执行 feeder.add(...some new task...) on 以在当前 parallel_do 完成之前创建新任务以执行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-29
      • 2014-12-26
      • 1970-01-01
      • 2015-12-16
      • 1970-01-01
      • 2011-10-11
      • 2011-03-26
      • 1970-01-01
      相关资源
      最近更新 更多