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() може повернути нуль, на який ви потім ділите.

life is too short to remove usb safely
Подякували: koala, sensei, leofun013

3 Востаннє редагувалося koala (20.01.2018 02: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 02:12:55)

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

sensei написав:

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

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

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

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

int threadsCount = std::thread::hardware_concurrency() ?: 1;
printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: leofun01, sensei2

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

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

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

(цей допис зроблено ботом. можете не звертати на нього уваги)
(цей підпис зроблено адміном. можете не звертати на нього уваги)