2

基本的に、私はオブジェクトのコレクションを持っています。それを小さなコレクションに切り刻み、小さなコレクションごとにスレッドでいくつかの作業を同時に行っています。

int totalCount =  SomeDictionary.Values.ToList().Count;
int singleThreadCount = (int)Math.Round((decimal)(totalCount / 10));
int lastThreadCount = totalCount - (singleThreadCount * 9);

Stopwatch sw = new Stopwatch();

Dictionary<int,Thread> allThreads = new Dictionary<int,Thread>();
List<rCode> results = new List<rCode>();

for (int i = 0; i < 10; i++)
{
    int count = i;

    if (i != 9)
    {
        Thread someThread = new Thread(() =>
        {
            List<rBase> objects =  SomeDictionary.Values
                                          .Skip(count * singleThreadCount)
                                          .Take(singleThreadCount).ToList();

            List<rCode> result = objects.Where(r => r.ZBox != null)
            .SelectMany(r => r.EffectiveCBox, (r, CBox) => new rCode
                                {
                                    RBox = r,
                                    // A Zbox may refer an object that can be 
                                    // shared by many 
                                    // rCode objects even on different threads
                                    ZBox = r.ZBox,
                                    CBox = CBox
                                }).ToList();

            results.AddRange(result);
        });

        allThreads.Add(i, someThread);
        someThread.Start();
    }
    else 
    {
        Thread someThread = new Thread(() =>
        {
            List<rBase> objects =  SomeDictionary.Values
                                           .Skip(count * singleThreadCount)
                                           .Take(lastThreadCount).ToList();

            List<rCode> result = objects.Where(r => r.ZBox != null)
            .SelectMany(r => r.EffectiveCBox, (r, CBox) => new rCode
                        {
                            RBox = r,
                            // A Zbox may refer an object that 
                            // can be shared by many 
                            // rCode objects even on different threads
                            ZBox = r.ZBox, 
                            CBox = CBox
                        }).ToList();

            results.AddRange(result);
        });

        allThreads.Add(i, someThread);
        someThread.Start();
    }
}

sw.Start();
while (allThreads.Values.Any(th => th.IsAlive))
{ 
    if (sw.ElapsedMilliseconds >= 60000) 
    { 
        results = null; 
        allThreads.Values.ToList().ForEach(t => t.Abort()); 
        sw.Stop(); 
        break; 
    } 
}

return  results != null ? results.OrderBy(r => r.ZBox.Name).ToList():null;

したがって、私の問題は、結果を返す前に OrderBy 操作を実行しているときに null 参照例外が発生し、例外がどこにあるかを正確に判断できなかったことです。再び同じデータ、そしてそれは動作します!! ..誰かがこの問題を特定するのを手伝ってくれるなら、私は感謝しています。注:Zbox は、異なるスレッドであっても多くの rCode オブジェクトで共有できるオブジェクトを参照する場合がありますが、これが問題になる可能性はありますか? エラーの発生は決定論的ではないため、テスト時にこれを判断できないためです。

4

3 に答える 3

2

私は答えに同意しませんが、バグは選択した答えで正しく見つかりました。並行コレクションの使用に切り替える必要があります。あなたの場合、ConcurrentBag または ConcurrentQueue です。パフォーマンスを向上させるために (部分的に) ロックフリーになっているものもあります。また、手動でロックする必要がないため、より読みやすく、より少ないコードを提供します。

また、手動で作成されたスレッドと手動のパーティション分割を避けると、コードのサイズが半分以上になり、可読性が 2 倍になります。

Parallel.ForEach(objects, MyObjectProcessor);

public void MyObjectProcessor(Object o)
{
  // Create result and add to results
}

Parallel.ForEach でスレッド数を制限したい場合は、ParallelOptions オブジェクトを使用してください。

于 2012-09-14T14:15:04.960 に答える
1

さて、1 つの明らかな問題がここにあります。

results.AddRange(result);

複数のスレッドからリストを更新している場所。ロックを使用してみてください:

object resultsLock = new object(); // globally visible
...
lock(resultsLock) 
{
    results.AddRange(result);
}
于 2012-09-14T10:11:30.903 に答える
0

結果の問題= nullだと思います

while (allThreads.Values.Any(th => th.IsAlive))
    { if (sw.ElapsedMilliseconds >= 60000) { results = null;  allThreads.Values.ToList().ForEach(t => t.Abort());

スレッドが 60000 ミリ秒よりも速く終了しない場合、結果は null になり、results.OrderBy(r => r.ZBox.Name).ToList(); を呼び出すことはできません。それは例外をスローします

そのようなものを追加する必要があります

if (results != null) 
  return  results.OrderBy(r => r.ZBox.Name).ToList();
else
  return null;
于 2012-09-14T09:45:23.440 に答える