1

私は電話していますvar person = PersonDB.pDict["395096"];

このコードがブロックされる理由を誰かに説明してもらえますか:

static class PersonDB
{
    internal static readonly ConcurrentDictionary<string, Person> pDict;

    static PersonDB()
    {
        pDict = new ConcurrentDictionary<string, Person>();
        var headers = File.ReadLines(FindPath.DataSetPerson).First().Split(';');


        File.ReadLines(FindPath.DataSetPerson).AsParallel().Skip(1).Select(s => s.Split(';')).ForAll(fa =>
           pDict.TryAdd(fa[0], new Person() { all = Enumerable.Range(0, fa.Length).ToDictionary(t => headers[t], d => fa[d]) })
        );
    }
}

sealed class Person
{
    public Dictionary<string, string> all;
}

この部分はブロックしませんが:

static class PersonDB
{
    internal static readonly ConcurrentDictionary<string, Person> pDict;

    static PersonDB()
    {
        pDict = new ConcurrentDictionary<string, Person>();
        var headers = File.ReadLines(FindPath.DataSetPerson).First().Split(';');


        //File.ReadLines(FindPath.DataSetPerson).AsParallel().Skip(1).Select(s => s.Split(';')).ForAll(fa =>
        //   pDict.TryAdd(fa[0], new Person() { all = Enumerable.Range(0, fa.Length).ToDictionary(t => headers[t], d => fa[d]) })
        //);

        Parallel.ForEach(File.ReadLines(FindPath.DataSetPerson).Skip(1).Select(s => s.Split(';')), line =>
        {
            pDict.TryAdd(line[0], new Person() { all = Enumerable.Range(0, line.Length).ToDictionary(t => headers[t], d => line[d]) });
        });

    }
}

sealed class Person
{
    public Dictionary<string, string> all;
}

正直なところ、後者が現在スレッドセーフであるかどうかさえわかりませんが、少なくとも問題なく動作します。競合状態やデッドロックが発生しないように、PersonDB をスレッド セーフなクラスにする方法を知りたいです。pDict は、pDict の使用時に一度作成する必要があります。静的コンストラクターはこれに対する優れた解決策だと思いましたが、PLINQ クエリの実行停止により、非常に不安になります...

4

1 に答える 1

3

これは、静的コンストラクターのデッドロックです。静的に初期化PersonDBされるまでブロックする並列スレッド アクセス。PersonDB初期化コードを別の関数に移動します。その場で変更するのではなく、辞書を返すようにpDictします。

失敗する可能性のあることを行う静的コンストラクターは避けようとしています。IO であるため、コードは確実に失敗する可能性があります。その場合、クラスは永続的にホースされます。Lazyより良いことができます。

于 2015-08-05T14:55:28.483 に答える