1

Тема: розпаралелити for

Доброго вечора всім

Мав я значить один фор, який опрацьовував вектор vertices

Вирішив я його пришвидшити потоками: виніс тіло фору в функцію і передаю в неї межі які кожен конкретний потік має опрацювати
А по завершенню всі вони мають синхронізуватись, на тому ж місці де це зробив би і однопоточний фор

Гляньте чи не наткнусь я таким чином на якісь підводні камені, та і взагальному чи є якісь зауваження

void threadFunc(int startInd, int endInd, const std::vector<Vector3> & vertices);
int start = 0;
int end = vertices.size() - 1;
int threadsCount = std::thread::hardware_concurrency();
int part = (end - start) / threadsCount;

std::vector<std::thread> threads(threadsCount);
for (int i = 0; i < threadsCount; ++i)
{
    int startInd = part * i;
    int endInd = (i == threadsCount - 1) ? end : part * (i + 1);
    threads[i] = std::thread(threadFunc, startInd, std::ref(vertices));
}
for (int i = 0; i < threadsCount; ++i)
{
    threads[i].join();
}

2

Re: розпаралелити for

int threadsCount = std::thread::hardware_concurrency();
int part = (end - start) / threadsCount;

std::thread::hardware_concurrency() може повернути нуль, на який ви потім ділите.

Подякували: koala, sensei, leofun013

3 Востаннє редагувалося koala (20.01.2018 01:00:11)

Re: розпаралелити for

Ну, по-перше, найцікавіше - те, що має відбуватися в циклі - ви нам не показали. А більшість підводних каменів саме там.
По-друге, ви забули передати в потік індекс кінця.
По-третє, ви дивно обчислюєте кількість операцій на потік. Припустимо, є 4 ядра і 15 об'єктів. Тоді:
end = 14;//!
part = 14 / 4 = 3;//!!!
Потоки отримають:
i = 0 => 3 елементи
i = 1 => 3 елементи
i = 2 => 3 елементи
i = 3 => 5 елементів
Разом - 14 елементів. І сподіваюся, ваші потоки лізуть на дані іншого.
Ну і по-четверте, не зовсім зрозуміло, нащо вам std::ref, тим більше, що threadFunc не reference_wrapper приймає.

Подякували: sensei, Arete, leofun013

4

Re: розпаралелити for

Arete написав:

std::thread::hardware_concurrency() може повернути нуль, на який ви потім ділите.

Якщо я впевнений в тому що в мому компіляторі цей метод реалізований, то нормально буде на перший час обійтись таким рішенням?

int threadsCount = std::thread::hardware_concurrency() || 1;
koala написав:

По-третє, ви дивно обчислюєте кількість операцій на потік. Припустимо, є 4 ядра і 15 об'єктів. Тоді:
end = 14;//!
part = 14 / 4 = 3;//!!!
Потоки отримають:
i = 0 => 3 елементи
i = 1 => 3 елементи
i = 2 => 3 елементи
i = 3 => 5 елементів
Разом - 14 елементів. І сподіваюся, ваші потоки лізуть на дані іншого.

Я забув, що я не на форумі телепатів та не уточнив, що [start; end) формують напів-відкритий проміжок

for (i = start; i < end; i++){}

Тобто у випадку коли є 15 об'єктів - end=16

Але ваше зауваження наштовхнуло мене трохи  переобити алгоритм для більш збалансованого розподілу

float part =  (float)(end - start) / (float)threadsCount;
for (int i = 0; i < threadsCount; ++i)
{
    int startInd = part * i;
    int endInd = part * (i + 1);
    threads[i] = std::thread(threadFunc, startInd, endInd, std::ref(vertices));
}

i = 0 => 3
i = 1 => 4
i = 2 => 4
i = 3 => 4

koala написав:

Ну і по-четверте, не зовсім зрозуміло, нащо вам std::ref, тим більше, що threadFunc не reference_wrapper приймає.

у reference_wrapper реалізований оператор приведення до посилання operator T& ()
і використовувати його потрібно тому, що оскільки аргументи з якими створюється потік копіюються в новий стек, то передавши аргумент який має бути посиланням без std::ref в потоці ми отримаємо посилання на скопійований обк'єкт

Прихований текст

The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with std::ref or std::cref).

Подякували: koala, Arete, leofun013

5 Востаннє редагувалося ReAl (21.01.2018 01:12:55)

Re: розпаралелити for

sensei написав:

Якщо я впевнений в тому що в мому компіляторі цей метод реалізований, то нормально буде на перший час обійтись таким рішенням?

int threadsCount = std::thread::hardware_concurrency() || 1;

Ой, а в C і C++ хіба це не має повертати завжди 1?

GNU отаке дозволяє (без --pedantic)

int threadsCount = std::thread::hardware_concurrency() ?: 1;
Подякували: leofun01, sensei2

6 Востаннє редагувалося Alchimic (28.01.2018 23:25:54)

Re: розпаралелити for

чувак 4 потоки максимум.. обслуговування потоків тяне нехило на.що ти розкошелився на чотирьох ксеонах працюєш чи що. 4 потока роби - максимальна швидкодія. Як правило паралелять на два. По госту 2005 го. 2018 на 4 паралелять. може в 2040 будуть як ти на 200 паралелити. коли буде 200 мікроядер.