Отвечает на многопоточное умножение матрицы в С++ 11

Вопрос: На данный момент у меня есть два потока для каждой из моих функций. Топор и Меч - это объекты Матрицы. thread thrd1(Add, std::ref(Axe), std::ref(Sword), std::ref(Axe)); thread thrd2(Multiply, std::ref(Axe), std::ref(Sword), std::ref(Axe)); Я новичок в нарезке и не совсем понимаю. Нужно ли добавлять потоки в мою функцию умножения? прямо сейчас это просто //Multiply the matrices void

Вопрос:

На данный момент у меня есть два потока для каждой из моих функций. Топор и Меч – это объекты Матрицы.

thread thrd1(Add, std::ref(Axe), std::ref(Sword), std::ref(Axe)); thread thrd2(Multiply, std::ref(Axe), std::ref(Sword), std::ref(Axe));

Я новичок в нарезке и не совсем понимаю. Нужно ли добавлять потоки в мою функцию умножения? прямо сейчас это просто

//Multiply the matrices void Multiply(Matrix &a, Matrix &b, Matrix &c){ for (auto i=0; i<c.dx; ++i) { for (auto j=0; j<c.dy; ++j) { for (auto k=0; k<a.dy; ++k) { c.p[i][j] += a.p[i][k] * b.p[k][j]; } } } }

но я чувствую, что мне нужно добавить что-то еще, из-за того, что они не уменьшают время, задавая количество потоков через openMP. Может кто-нибудь мне помочь?

Ответ №1

Все, что вам нужно сделать, это

void Multiply(Matrix &a, Matrix &b, Matrix &c) { #pragma omp parallel for for (int i=0; i<c.dx; ++i) { for (int j=0; j<c.dy; ++j) { for (int k=0; k<a.dy; ++k) { c.p[i][j] += a.p[i][k] * b.p[k][j]; } } } }

Вероятно, вы не хотите беспокоиться о количестве потоков. Просто дайте OpenMP выбрать значение по умолчанию. Это будет установлено на количество логических ядер. Однако, если у вас есть гиперпоточность, это может помочь установить количество потоков в число физических ядер, а не количество логических ядер.

Вы также можете попробовать слить петлю. Как это

#pragma omp parallel for for(int n=0; n<c.dx*c.dy; n++) { int i=n/c.dy; int j=n%c.dy;

Однако, когда вы читаете bp[k][j] него, вероятно, будет много промахов в кеше. Гораздо лучшее решение – взять транспонирование b и получить доступ к транспонированию как bp [j] [k].

Еще лучшее решение – использовать умножение матричных/блочных матриц. См. Следующую ссылку о том, как это сделать: чтение/запись матрицы с шагом намного больше, чем ее ширина, приводит к большой потере производительности

Ответ №2

Прежде всего: OpenMP и std :: thread/future/etc. это разные вещи. Если вы хотите использовать OpenMP, есть несколько неплохих учебников, которые нужно искать, но это сводится к одной команде препроцессора перед вашим первым циклом, я думаю.

Теперь в часть С++ 11: я думаю, из вашего вопроса (в этом было совершенно непонятно), что вы передаете свою функцию для запуска в потоке. Это не уменьшит время вычисления, так как ваш код все еще работает в одном потоке. Теперь угадайте, что означает “multi” в “многопоточности”…

То, что вы хотите делать каждый раз, когда пишете многопоточный код,

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

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

  3. Напишите функцию, которая выполняет такую подзадачу (например, ограничьте свою функцию вычислением только одного столбца, который вы передаете в качестве параметра), и для всех подзадач создайте объекты std :: thread или std :: future (последний с использованием std :: async), передайте им свою функцию подзадачи с соответствующими параметрами и дождитесь их завершения (используя thread :: join).

Имейте в виду, что при написании многопоточного кода для менее простых вопросов на любом не чисто функциональном языке может быстро стать довольно сложным. Вероятно, вам нужно потратить некоторое время и прочитать некоторые учебники или книги. Для начала, возможно, загляните в этот список youtube:

О, и прежде, чем я забуду это: в вашей функции вам не нужно писать ни в a ни в b и поэтому следует передавать их по ссылке const. На строительной площадке нити вам придется использовать std::cref. Константа правильности очень важна при написании многопоточного кода.

Оцените статью
Добавить комментарий