C# 静态构造函数在填充 ConcurrentDictionary 时初始化线程安全
C# static constructor initialization thread safety while filling ConcurrentDictionary
我打电话给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 成为线程安全的 class,从而不会出现竞争条件或死锁。 pDict 需要在使用 pDict 时创建一次。我认为静态构造函数是一个很好的解决方案,但是 PLINQ 查询的执行停止让我非常不确定...
这是静态构造函数死锁。并行线程访问 PersonDB
,它会阻塞,直到 PersonDB
被静态初始化。将初始化代码移动到不同的函数。使其 return 成为字典,而不是就地修改 pDict
。
我尽量避免使用可能会失败的静态构造函数。您的代码肯定会失败,因为它是 IO。如果确实如此,class 将被永久性地冲洗掉。 Lazy
可以更好。
我打电话给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 成为线程安全的 class,从而不会出现竞争条件或死锁。 pDict 需要在使用 pDict 时创建一次。我认为静态构造函数是一个很好的解决方案,但是 PLINQ 查询的执行停止让我非常不确定...
这是静态构造函数死锁。并行线程访问 PersonDB
,它会阻塞,直到 PersonDB
被静态初始化。将初始化代码移动到不同的函数。使其 return 成为字典,而不是就地修改 pDict
。
我尽量避免使用可能会失败的静态构造函数。您的代码肯定会失败,因为它是 IO。如果确实如此,class 将被永久性地冲洗掉。 Lazy
可以更好。