C# C静态构造函数初始化线程安全,同时填充ConcurrentDictionary

C# C静态构造函数初始化线程安全,同时填充ConcurrentDictionary,c#,multithreading,thread-safety,plinq,static-constructor,C#,Multithreading,Thread Safety,Plinq,Static Constructor,我打电话给var person=PersonDB.pDict[395096] 谁能解释一下为什么这个代码会阻塞: static class PersonDB { internal static readonly ConcurrentDictionary<string, Person> pDict; static PersonDB() { pDict = new ConcurrentDictionary<string, Person>

我打电话给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查询上的执行停止让我非常不确定…

这是一个静态构造函数死锁。并行线程访问PersonDB,直到PersonDB静态初始化为止。将初始化代码移到其他函数。使其返回字典,而不是在适当的位置修改pDict


我尽量避免使用静态构造函数来做可能失败的事情。您的代码肯定会失败,因为它是IO。如果是这样的话,这个班级将被永久性地用水管冲洗。懒惰可能更好。

Skip1可能会跳过任何一行,因为您的查询没有排序。所有这些可能都没有意义,因为CD比普通字典慢得多。只要使用普通的字典,它就会更快。可能CSV行解析可以从并行性中受益,但开销很高。Skip1只是为了跳过CSV文件的标题,用parallel foreach填充普通字典会导致并行线程同时写入字典,这会导致错误,所以concurrentdictionary在这里是必要的,但如果我错了,请纠正我,我不是这方面的专家。我理解跳过的原因,但它可以跳过任何行,因为查询是无序和并行的。;是的,CD需要并行,但并行写入CD速度较慢。这比不平行地写字典要慢。如果没有任何并行性,这可能会更快。@BigChief,但问题是,在这里并行化代码会使速度变慢。事实上,您可以并行化完全不同的代码块并使其受益,这与此无关。感谢usr,如何在这里实现Lazy。。??我最好只做另一个函数GetDictionarystring id,它在其中返回字典以使这项工作正常进行……嗯,是的,这是我的第一个建议。那就行了。