1

リストに含まれる大量のオブジェクトを可能な限り迅速に組み合わせる方法を考え出そうとしています。PLINQを利用したいと思って試しましたが、これはスレッドセーフなソリューションではありません。4.0と4.5のVS2010とVS11Betaでテストしました。これは私のサンプルアプリです。BlowUp()を1〜500の間で変更すると、通常は機能します。500を過ぎると、車輪が軌道から外れます。複数の場所で失敗します。この問題を解決する最速の方法を知っている人はいますか?(多次元配列+ PLINQ?)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PLinqBlowsUp
{
class Program
{
    static void Main(string[] args)
    {
        BlowUp(5000);
    }

    private static void BlowUp(int blowupNum)
    {
        try
        {
            var theExistingMasterListOfAllRowsOfData = new List<List<KeyValuePair<string, dynamic>>>();

            //Add some test data
            Enumerable.Range(0, blowupNum).AsParallel().ForAll(row => theExistingMasterListOfAllRowsOfData.Add(AddRowToMasterList(row)));


            var aNewRowOfData = new List<KeyValuePair<string, dynamic>>();
            //Add some test data
            var column = new KeyValuePair<string, dynamic>("Title", "MyTitle");
            aNewRowOfData.Add(column);

            var anotherNewRowOfData = new List<KeyValuePair<string, dynamic>>();
            //Add some test data
            var columnA = new KeyValuePair<string, dynamic>("Date", DateTime.Now);
            var columnB = new KeyValuePair<string, dynamic>("ImportantColumn", "ImportantData");
            var columnC = new KeyValuePair<string, dynamic>("VeryImportantColumn", "VeryImportantData");
            anotherNewRowOfData.Add(columnA);
            anotherNewRowOfData.Add(columnB);
            anotherNewRowOfData.Add(columnC);

            //Now the Problem
            aNewRowOfData.AsParallel().ForAll(anrod => theExistingMasterListOfAllRowsOfData.ForEach(temloarod => temloarod.Add(anrod)));
            anotherNewRowOfData.AsParallel().ForAll(anrod => theExistingMasterListOfAllRowsOfData.ForEach(temloarod => temloarod.Add(anrod)));

            //Test for number
            foreach (var masterRow in theExistingMasterListOfAllRowsOfData)
            {
                if (masterRow.Count != 7)
                    throw new Exception("BLOW UP!!!");
            }
        }
        catch (AggregateException ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    private static List<KeyValuePair<string, dynamic>> AddRowToMasterList(int row)
    {
        var columnA = new KeyValuePair<string, dynamic>("FirstName", "John" + row.ToString());
        var columnB = new KeyValuePair<string, dynamic>("LastName", "Smith" + row.ToString());
        var columnC = new KeyValuePair<string, dynamic>("Ssn", 123456789 + (row*10));

        var list = new List<KeyValuePair<string, dynamic>>();
        list.Add(columnA);
        list.Add(columnB);
        list.Add(columnC);
        return list;
    }
}
}
4

3 に答える 3

4

これはPLinqとは何の関係もありません-にアイテムを追加することList<T>は単にスレッドセーフではありません。ただし、ロックを導入することでパフォーマンスを低下させる実行可能なソリューション。代わりに通常やりたいことは、PLinqステートメントの結果として新しいコレクションに投影することです-あなたがしたような副作用を導入することは、Linq /関数型プログラミングの精神ではなく、問題にぶつかる可能性があります(あなたがした)。

于 2012-05-22T17:11:57.177 に答える
3

2つの問題があります。

  • インスタンスへのアクセスを同期しようとせずに、複数のスレッドからインスタンスを呼び出しAddています。theExistingMasterListOfAllRowsOfData
  • 同期を試みずに、複数のスレッドからAdd個々のアイテムを呼び出しています。List<KeyValuePair<string, dynamic>>

メソッドlockを保護するために使用することも、代わりに使用することもできます。ただし、これらのオプションはどちらもそれほど優れていません。ここでの問題は、すべてのスレッドが同じロックをめぐって競合するため、この種の操作をうまく並列化できないことです。ローロックでさえ、PLINQでパントして、最初にメインスレッドですべてを実行した場合よりも遅くなるのではないかと強く思います。AddConcurrentBagConcurrentBag

于 2012-05-22T18:24:06.530 に答える
2

PLinqは、スレッドセーフなコードを書くことに代わるものではありません。theExistingMasterListOfAllRowsOfDataスレッドプールのすべてのスレッドがアクセスしているため、へのアクセスはスレッドセーフではありません。あなたはそれの周りをロックしてみることができます、それは私にとって問題を解決しました:

Enumerable.Range(0, blowupNum).AsParallel().ForAll(row => {
    lock (theExistingMasterListOfAllRowsOfData) {                 
        theExistingMasterListOfAllRowsOfData.Add(AddRowToMasterList(row));
    }
});

ただし、ロックはボトルネックを引き起こすため、目的のロックではない場合があります。

于 2012-05-22T17:11:33.303 に答える