Это мой первый пост здесь, хотя я регулярно посещаю сайт и нахожу здесь много полезной информации.Почему производительность этого неловко параллельного алгоритма не улучшается при многопоточности?
У меня есть смущающий параллельный алгоритм, который, как я ожидал, продемонстрирует большие улучшения производительности при многопоточности.
Это мой первый опыт многопоточности, после небольшого количества чтения и обзора.
Я работаю на C++ с VS 2012, а мой ноутбук с Windows 7 оснащен процессором i7 с четырьмя ядрами и большим количеством памяти.
Основная работа распадается на этот псевдокод
for (int i = 0; i<iMax; i++){
for (int j = 0; j<jMax; j++){
T[j] += E[j][i] * SF;
}
}
Т, Е и SF являются поплавками.
Реализация использует (измененную) threadpool от here.
и строит и добавляет кучу задач для ThreadPool от этой функции
void doWork(float *T, float *E, float SF, int numNodes)
{
// Critical for performance that these loops vectorize.....
for (int nodeCounter = 0; nodeCounter < numNodes; nodeCounter++){
T[nodeCounter] += E[nodeCounter] * SF;
}
};
используя эту конструкцию,
tp.enqueue(std::bind(&doWork, timeStepDisplacements.T1, T1MODE, T1MPF, numNodes));
в моих тестах, numNodes является 1000000 и я называю это рутинные 3 раза (с разными массивами) для каждой из 50 внешних петель. У меня есть еще одна петля (100) вокруг нее тоже, поэтому мой тестовый код генерирует этих задач с каждой задачей, выполняющей 1,000,000 умножений.
EDIT: Corrected внешнего счетчика цикла до 100 и числа задач, от 7500 до 15000
Когда я создал мой ThreadPool с 8, 16 или более нитями, производительность лишь незначительно лучше, чем последовательный код - скажем, 8,8 секунды против 9,3.
Итак, мой вопрос в том, почему улучшение производительности настолько мало?
ПРИМЕЧАНИЕ. Если используется другая задача (work_proc ниже), то такая же настройка потока потока показывает отличную прибыль.
void work_proc()
{
int i = 555;
std::random_device rd;
std::mt19937 rng(rd());
// build a vector of random numbers
std::vector<int> data;
data.reserve(100000);
std::generate_n(std::back_inserter(data), data.capacity(), [&](){ return rng(); });
std::sort(data.begin(), data.end());
}
У меня нет проблем с отправкой всего кода, но я решил, что начну с этих ключевых элементов.
Thanx заранее для любого понимания, которое будет предложено.
Приращение 'j' во внутреннем цикле может означать много промахов в кэше. Возможно, попробуйте рефакторинг цикла, чтобы он был более дружественным к кешу. –
Поддерживает ли ваша ОС потоки на отдельных ядрах или же ядро? –
Имеет ли в каждом ядре отдельный процессор с плавающей запятой или аппаратное обеспечение? –