Многие из нас, вероятно, начнут с реализации чего-то непараллельным образом, а затем потребуют рефакторинга кода и использования параллелизма. Есть ли какая-либо теория или предложение о том, как эффективно находить функции горячих точек или фрагменты кода для параллелизма.
Например, у меня может быть следующий фрагмент кода в непараллельном стиле:
int[] data = new int[1000000]; // Just a big trunk of data.
// Here is just a procedure on the trunk of data, performing repeated work.
void SequentialProcedure(){
for(int i = 0; i < data.Length; i++) data[i] += rand.Next();
}
Для такого парня, как я, без особого опыта параллелизма, на первый взгляд, это выглядело бы как функция, которую можно применить с каким-нибудь изумительным навыком параллелизма:
int[] data = new int[1000000]; // The same big trunk of data.
// A parallel implementation.
void ParallelProcedure(){
Parallel.ForEach(Partitioner.Create(0, data.Length),
range => {
for(int i = range.Item1; i < range.Item2; i++) data[i] += rand.Next();
}
);
}
OK. Хотя я читаю что-то и знаю, что реальная задача добавления случайного числа к каждому элементу вектора мала по сравнению со стоимостью создания делегатов и использования диапазонов, чтобы сделать каждую параллельную задачу более мясной, параллельная версия все еще медленнее, чем последовательная версия , В этот момент я потеряюсь: значит, SequentialProcedure - это просто функция, не подходящая для параллелизма? или способ, которым я пытаюсь распараллелить это просто неправильно? есть ли какие-то предложения, указания от гуру, которым мы можем следовать при определении того, где параллелизм будет иметь больший эффект, а где параллелизм будет просто пустой тратой времени?
Большое спасибо за любую помощь.
Edit:
Чтобы сделать каждую итерацию более мясной, я добавляю итерацию второго уровня. Таким образом, последовательный код становится:
int[] data = new int[100];
void SequentialProcedure(){
for(int i = 0; i < data.Length; i++){
for(int j = 0; j < 500000; j++) data[i] = rand.Next(j, Int32.MaxValue);
}
}
И параллельная версия становится:
int[] data = new int[100];
void ParallelProcedure(){
Parallel.ForEach(Partitioner.Create(0, data.Length),
range => {
for(int i = range.Item1; i < range.Item2; i++){
for(int j = 0; j < 500000; j++) data[i] = rand.Next(j, Int32.MaxValue);
}
}
}
Интересно видеть, что даже теперь у каждой внешней итерации достаточно работы, параллельная процедура все еще почти в 4 раза медленнее, чем последовательная процедура на моем компьютере.
Возможна ли проблема выделения памяти / кэширования?
Редактировать: по-видимому, это менее вероятно проблема памяти, которая вызывает замедление параллели в приведенном выше примере. Действительно нужно выяснить причину ...