ppl, как им правильно пользоваться?

Следующий код:

#include <ppl.h>
int i;
vector<int> val(10),summ(10,0);
for(i=0;i<10;i++) val[i]=i;

parallel_for(0, 10, [&] (int y){
    vector<int> vett(1000);
    double vall=val[y];

    for(i=0;i<vett.size();i++)
        vett[i]=vall;

    for(i=0;i<vett.size();i++)
        summ[y]+=vett[i];
 });

for(i=0;i<10;i++)
cout<<summ[i]<<endl;

Производит случайный вывод, например: 0 1000 1468 204 3600 25 5898 7000 7456 1395

Думаю, мне следует использовать «combinable», но документация, которую я нашел по этому поводу, не очень хороша. Вы знаете, как заставить этот код работать правильно? Что, если vett — двумерный вектор?

Поскольку я хотел бы изучить параллельные вычисления, стоит ли изучать эту новую библиотеку Microsoft или есть лучшие альтернативы?


person MarcoS    schedule 13.02.2012    source источник
comment
Какую документацию вы используете? Я нашел среду выполнения с параллелизмом и Параллельное программирование с помощью Microsoft Visual C++ очень полезно.   -  person Blastfurnace    schedule 14.02.2012


Ответы (2)


Основная проблема с вашим кодом - переменная индекса i. Он используется несколькими параллельными задачами одновременно. Возникает хаос, который и является причиной сомнительных результатов. Самое простое решение — объявить циклы в вашей лямбде следующим образом:

for(int i=0;i<vett.size();i++)
    vett[i]=vall;

for(int i=0;i<vett.size();i++)
    summ[y]+=vett[i];

Обратите внимание, что каждый индекс цикла объявляется при инициализации цикла for. Это более идиоматическое использование, и его можно использовать во всех ваших циклах, если только вам действительно не нужно конечное значение i после завершения цикла.

person Blastfurnace    schedule 14.02.2012
comment
чтобы уточнить, все переменные, объявленные в parallel_for, являются общими для ступеней? поэтому, объявляя i в инициализации for, вы избегаете этого. - person MarcoS; 14.02.2012
comment
@MarcoS: лямбда-выражение в вашем коде захватило i во внешней области по ссылке. Это означало, что несколько задач совместно использовали эту единственную переменную. Если вы объявите переменную внутри лямбды, то каждая задача получит свой собственный экземпляр i. При объявлении i в инициализации цикла for время жизни еще больше ограничивается только телом цикла. - person Blastfurnace; 14.02.2012
comment
Спасибо, только что объявил еще один int внутри for_loop, и результаты больше не случайны. И я знаю почему. Хороший - person MarcoS; 14.02.2012

Хорошее эмпирическое правило для параллельного кода — минимизировать количество общих переменных.

Как следствие, вы никогда не должны использовать [&] в качестве лямбда-захвата для parallel_for (или std::thread). Захватывайте только те переменные, которые необходимо использовать совместно.

Если бы вы сделали это, вы бы обнаружили проблему, указанную @Blastfurnace, а именно, что i был разделен между всеми работниками.

person Ben Voigt    schedule 14.02.2012
comment
Я не слишком много знаю о лямбда-функциях, поэтому не понимаю, что вы имеете в виду под [&]. Вы имеете в виду индекс «parallel_for»? Я обнаружил, что в качестве стандартного примера это можно изменить? Кажется, что лямбда-функции стоят на первом месте при попытке выучить ppl. - person MarcoS; 14.02.2012
comment
@MarcoS: это не индекс. Это лямбда-выражение, которое создает функторный объект. И да, вы должны прочитать о лямбда-выражениях, прежде чем использовать их с PPL. Например: blogs.msdn.com/b/vcblog/archive/2008/10/28/ - person Ben Voigt; 14.02.2012