私は反復関数を反復型に変換してから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
の最後の反復の4番目のスレッドでありますループ私は、インデックスは、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コアまで拡大することを期待しています。スレッドに固執している場合、私は 'Join'sをどこかに見ることを期待しています。そうしないと、前のバッチが終了する前に各ループの繰り返しでスレッドがますます多くなり始めます。 –
アルゴリズムは正しいですか?私の理解のところでは、 'for(int j =((i/maxThreads)* length); j <(((i + 1)/ maxThreads)* length); j + = N) [0、maxThreads-1]の範囲では、int j =((i/maxThreads)* length'は常に0になります(これは整数除算です)/maxThreads)* length) '最後のものを除いてすべての' i'値に対して 'false'になるので、最後に内部ループは何スレッドで使用されても1回だけ入力されます – qbik