2014-01-09 4 views
2

Прежде всего я создал пул потоков и попытался выполнить некоторые тяжелые арифметические операции над массивом размером 40960 элементов float.C++ 11 параллельный для реализации

Однопоточный подход получил результат 0,0009 секунды, в то время как параллельный подход с 4 потоками, выполняемый синхронно, получил 0,0003 секунды. В этой реализации я вручную распределил задачу на 4 части и поставил их в пул потоков.

Теперь я хочу предоставить общий метод parfor для моего пула потоков. Я пробовал:

void parfor(int begin, int end, std::function<void(int)>func) 
    { 
     int delta = (end - begin)/M_count; 
     for (int i = 0; i < M_count; ++i) 
      queue([=]{ 
       int localbegin = begin + i*delta; 
       int localend = (i == M_count - 1) ? end : localbegin + delta; 
       for (int it = localbegin; it < localend; ++it) 
        func(it); 
      }); 
     wait(); 
    } 

Где M_count - количество потоков. И время выполнения составляет 0,003 секунды (примерно в 10 раз больше, чем при ручном распределении задания). Я предполагаю, что std :: function имеет большие накладные расходы во время выполнения, но не знает другого альтернативного подхода. Не могли бы вы дать мне совет? Большое спасибо.

Edit: По совету Rapptz, я попытался это:

template <typename Function> 
void parfor(int begin, int end, Function) 

И использовали его, как это:

pool.parfor(0, 40960, [&](int i){ 
    buff[i] = pow5(buff[i]); 
}); 

Это показывает некоторые ошибки:

error C2371: 'it' : redefinition; different basic types 
error C2512: 'wmain::<lambda_badf06dfbebc4bb15b3ade2b922c7f76>' : no appropriate default constructor available 

Я думаю, он относится к лямбда как к типу, но не знает, как ее решить ...

+0

Возможно, ваша версия руководства может встроить функцию, в то время как 'parfor' явно не может. – woolstar

+2

Используйте шаблон вместо 'std :: function'. – Rapptz

+0

@ woolstar Да, я так думаю. Но не знаю, как заставить функцию inline в моем парфоре. – babel92

ответ

2

(Слишком много для комментария ...) Это просто объясняет, как реализовать предложение Rapptz об использовании параметра шаблона для указания функции (поэтому она может быть встроена).

Рассмотрим следующий код:

#include <iostream> 

void f(int n) { std::cout << "f(" << n << ");\n"; } 
void g(int n) { std::cout << "g(" << n << ");\n"; } 

template <typename Function> 
void t(Function function, int n) 
{ 
    static int x; 
    std::cout << "&x " << &x << '\n'; 
    function(n); 
} 

struct FuncF { static void f(int n) { std::cout << "Ff(" << n << ");\n"; } }; 
struct FuncG { static void f(int n) { std::cout << "Gf(" << n << ");\n"; } }; 

template <typename Function> 
void ft(int n) 
{ 
    static int x; 
    std::cout << "&x " << &x << '\n'; 
    Function::f(n); 
} 

int main() 
{ 
    t(f, 42); 
    t(g, 42); 

    ft<FuncF>(42); 
    ft<FuncG>(42); 
} 

Это печатает что-то вроде:

&x 00421760 
f(42); 
&x 00421760 
g(42); 
&x 00421764 
Ff(42); 
&x 00421768 
Gf(42); 

Обратите внимание, что первые две печати и тот же адрес для x ... это потому, что только один конкретизацией шаблона необходимо, поскольку тип функции является одним и тем же для обоих вызовов. Шаблон ft использует параметр шаблона для доступа к функции без использования аргумента функции времени выполнения, поэтому есть два экземпляра, которые дают разные адреса для локального статического x.

Чтобы получить функциональные вызовы в строгом соответствии, вы должны принять подход, похожий на FuncF/FuncG и ft.

+0

Спасибо! Это так блестяще, и это работает! Я только что напомнил, что это что-то вроде функтора ... Но то, что меня расстраивает, - это однопоточный код, который работает быстрее, чем мой parfor при выпуске ... – babel92

+0

@ babel92: ну, 40960 не так много поплавков, а 0.0009 - это жесткое время бить после запуска/синхронизации потока. Вы можете получить гораздо лучшие результаты, если сможете использовать инструкции процессора или графического процессора для параллельной обработки реального числа (я их никогда не использовал, но думаю, что некоторые из них были добавлены в дополнение к инструкциям MMX и/или SSE). –

+0

После увеличения массива до 409600 преимущество резьбы стало очевидным :) На самом деле это всего лишь эксперимент. Большое спасибо. – babel92

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