Итак, я преобразовал рекурсивную функцию в итеративную, а затем использовал Parallel.ForEach, но когда я запускал ее через VTune, она использовала только 2 логических ядра в течение большей части времени выполнения.Переход от Parallel.ForEach к многопоточности
я решил попытаться использовать управляемые темы вместо этого, и превращали этот код:
for (int N = 2; N <= length; N <<= 1)
{
int maxThreads = 4;
var workGroup = Enumerable.Range(0, maxThreads);
Parallel.ForEach(workGroup, i =>
{
for (int j = ((i/maxThreads) * length); j < (((i + 1)/maxThreads) * length); j += N)
{
for (int k = 0; k < N/2; k++)
{
int evenIndex = j + k;
int oddIndex = j + k + (N/2);
var even = output[evenIndex];
var odd = output[oddIndex];
output[evenIndex] = even + odd * twiddles[k * (length/N)];
output[oddIndex] = even + odd * twiddles[(k + (N/2)) * (length/N)];
}
}
});
}
В это:
for (int N = 2; N <= length; N <<= 1)
{
int maxThreads = 4;
Thread one = new Thread(() => calculateChunk(0, maxThreads, length, N, output));
Thread two = new Thread(() => calculateChunk(1, maxThreads, length, N, output));
Thread three = new Thread(() => calculateChunk(2, maxThreads, length, N, output));
Thread four = new Thread(() => calculateChunk(3, maxThreads, length, N, output));
one.Start();
two.Start();
three.Start();
four.Start();
}
public void calculateChunk(int i, int maxThreads, int length, int N, Complex[] output)
{
for (int j = ((i/maxThreads) * length); j < (((i + 1)/maxThreads) * length); j += N)
{
for (int k = 0; k < N/2; k++)
{
int evenIndex = j + k;
int oddIndex = j + k + (N/2);
var even = output[evenIndex];
var odd = output[oddIndex];
output[evenIndex] = even + odd * twiddles[k * (length/N)];
output[oddIndex] = even + odd * twiddles[(k + (N/2)) * (length/N)];
}
}
}
Проблема заключается в четвертом потоке на последней итерации N
loop Я получаю исключение index out of bounds для выходного массива, где индекс пытается получить доступ к эквиваленту length
.
Я не могу определить причину с помощью отладки, но я считаю, что она связана с потоками, я запускал код без потоков, и он работал по назначению.
Если какой-либо из кодов нуждается в изменении, сообщите мне, как правило, несколько человек предлагают изменения. Спасибо за вашу помощь, я попытался разобраться в этом сам и довольно уверен, что проблема возникает в моей потоковой передаче, но я не вижу, как это сделать.
PS: Целью является распараллеливание этого сегмента кода.
[Parallel.ForEach] (https://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.foreach (v = vs.110) .aspx) имеет много перегрузок, вы можете контролировать степень параллелизма с вариантами. – davidshen84
Вы можете потенциально достичь желаемого результата, просто переместив 'Parallel.ForEach' из внутреннего цикла во внешний цикл вашего исходного фрагмента (если вы ожидаете, что он будет содержать больше элементов, чем' workGroup', конечно). Это уменьшит затраты на установку и выключение Parallel.ForEach и позволит балансировщику нагрузки лучше выполнять свою работу, и я ожидаю, что он масштабируется до N ядер. Если вы придерживаетесь нитей, я ожидаю увидеть «Присоединиться где-то», иначе вы начинаете все больше и больше потоков на каждой итерации цикла до того, как предыдущая партия сможет закончить. –
Вы уверены, что ваш алгоритм верен?По моему мнению, в цикле 'for (int j = ((i/maxThreads) * length); j <((i + 1)/maxThreads) * length); j + = N)' inital value ' int j = ((i/maxThreads) * length' всегда будет 0 для i в диапазоне [0, maxThreads-1] (это целочисленное деление!), а условие цикла j <((i + 1)/maxThreads) * length) 'будет' false' для всех значений 'i', за исключением последнего. Таким образом, в конце вы внутренний цикл вводится только один раз, независимо от того, сколько потоков вы используете. – qbik