2012-05-14 3 views
0

Извините, мне кажется, не получается intel's TBB кажется отличным & поддерживается, но я не могу окунуться в голову, как его использовать, так как я думаю, что я не привык думать о параллелизме с точки зрения задач, но вместо этого видел его как нитки.TBB для рабочей нагрузки, которая продолжает меняться?

В моей рабочей нагрузке есть работа, которая отправляет работу в очередь для продолжения обработки (подумайте о рекурсии, но вместо того, чтобы называть себя, она отправляет работу в очередь). Способ, которым я работал на Java, заключался в создании параллельной очереди (неблокирующей очереди) и threadpoolexecutor, которая работала над работой очереди/отправки. Но теперь я пытаюсь сделать что-то подобное в 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 ядер).

Может кто-нибудь помочь мне понять, как достичь моих задач, а также предложить лучший способ думать о TBB, исходящий из среды потоковой передачи Java (также у меня нет верности TBB, поэтому, если есть что-то более простое/лучшее, Я с удовольствием узнаю об этом. Мне просто не нравится C++ threadpool, потому что он, похоже, не активно развивается)?

+0

Что такое тип данных Context? Первоначально был класс DoWork '? – moshbear

+0

@moshbear для простоты, я просто сделал это int в примере. когда я действительно это делаю, это int и список. извините, должен был просто включить его int в примере. – Lostsoul

+0

Настоящий STL перевод вашего кода: http://codepad.org/vs4S1UtB. Вы должны идти оттуда. – moshbear

ответ

1

Подход, основанный на наличии очереди элементов для параллельной обработки, где каждый поток просто выталкивает один элемент из очереди и продолжает (и, возможно, добавляет новый элемент в конец очереди в какой-то момент), в корне неверен, поскольку это ограничивает параллелизм приложения. Очередь становится единственной точкой синхронизации, и потоки должны ждать, чтобы получить доступ к следующему элементу для обработки. На практике этот подход работает, когда задачи (каждое задание обработки каждого элемента) достаточно велики и выполняются в разное время, что позволяет сократить количество очередей, в отличие от того, когда (большинство) потоков завершаются одновременно и поступают в очередь для их следующих предметов для обработки.

Если вы пишете несколько многократно используемых фрагментов кода, вы не можете гарантировать, что задачи достаточно велики или они отличаются по размеру (время выполнения).

Я предполагаю, что вы используете шкалы приложений, что означает, что вы начинаете с некоторого значительного количества элементов (намного больше, чем количество потоков) в вашей очереди, и когда потоки выполняют обработку, они добавляют достаточное количество заданий до конца, так что есть достаточная работа для всех, пока приложение не завершится.

Если это так, я предпочел бы, чтобы вы сохранили два вектора, защищенные потоком ваших элементов (например, параллельные_объекты TBB) для взаимозаменяемости. Вы начинаете с одного вектора (ваш начальный набор элементов), и вы выполняете задачу enque() (я думаю, что это описано где-то в главе 12 справочного руководства TBB), которая выполняет параллель для начального вектора элементов. В то время как первая партия обрабатывается, вы будете push_back добавлять новые элементы во второй concurrent_vector, и когда вы закончите с первой, вы запустите() задачу с помощью параллельного_ над вторым вектором и начнете толкать новые элементы обратно в первый , Вы можете попробовать и наложить параллельную обработку элементов лучше, имея три вектора вместо двух и постепенно перемещаясь между ними, пока еще достаточно работы для того, чтобы весь поток был занят.

1

То, что вы пытаетесь сделать, - это именно то, для чего предназначен TBB parallel_do.«Тело», вызываемое parallel_do, передается аргументом «фидер», который вы можете сделать feeder.add(...some new task...) во время обработки задач для создания новых задач для выполнения до завершения текущего parallel_do.

Смежные вопросы