Вопрос:
На данный момент у меня есть два потока для каждой из моих функций. Топор и Меч – это объекты Матрицы.
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” в “многопоточности”…
То, что вы хотите делать каждый раз, когда пишете многопоточный код,
-
Подумайте о том, как вы можете разделить свою работу на (в идеальном случае одинаковые) проблемы с развязкой. Непересекающееся здесь означает, что все, что вы вычисляете, не зависит от результатов других вычислений. В вашем случае обратите внимание, что вычисление одного результирующего элемента матрицы или столбца/строки может быть вычислено независимо от других.
-
Независимо от того, какая такая запись “подкомпьютера” должна быть записана в место, в которое другие записи одновременно не записываются. Если это необходимо, есть способы обойти это (например, мьютексы), но часто проблемы могут быть определены как неотъемлемо независимые в памяти (так как в вашем случае каждый рабочий поток должен писать только в одном столбце, например).
-
Напишите функцию, которая выполняет такую подзадачу (например, ограничьте свою функцию вычислением только одного столбца, который вы передаете в качестве параметра), и для всех подзадач создайте объекты std :: thread или std :: future (последний с использованием std :: async), передайте им свою функцию подзадачи с соответствующими параметрами и дождитесь их завершения (используя thread :: join).
Имейте в виду, что при написании многопоточного кода для менее простых вопросов на любом не чисто функциональном языке может быстро стать довольно сложным. Вероятно, вам нужно потратить некоторое время и прочитать некоторые учебники или книги. Для начала, возможно, загляните в этот список youtube:
О, и прежде, чем я забуду это: в вашей функции вам не нужно писать ни в a ни в b и поэтому следует передавать их по ссылке const. На строительной площадке нити вам придется использовать std::cref. Константа правильности очень важна при написании многопоточного кода.