2015-08-05 3 views
1

Я звоню var person = PersonDB.pDict["395096"];C# статический конструктор безопасности инициализации нити при заполнении ConcurrentDictionary

Может кто-нибудь объяснить мне, почему этот код блоки:

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 делает меня очень неуверенным ...

+1

Пропуск (1) может пропустить любую строку, потому что ваш запрос не упорядочен. – usr

+1

Все это, вероятно, спорный, потому что CD гораздо медленнее, чем обычный словарь. Просто используйте обычный словарь, и он будет быстрее. * Возможно, анализ синтаксиса CSV может выиграть от параллелизма, но при высоких накладных расходах. – usr

+0

Пропустить (1), чтобы просто пропустить заголовок файла csv, заполнение обычного словаря с помощью параллельного foreach заставляет параллельные потоки записывать в словарь одновременно, что вызывает ошибки, поэтому здесь необходим параллельный запрос (но исправьте меня если я ошибаюсь, я не эксперт в этом) – BigChief

ответ

2

Это тупик статического конструктора. Доступ к параллельным потокам PersonDB, который блокируется до PersonDB, статически инициализируется. Переместите код инициализации в другую функцию. Заставьте его вернуть словарь вместо изменения pDict на место.

Я стараюсь избегать статических конструкторов, которые делают то, что может потерпеть неудачу. Ваш код, конечно, может выйти из строя, потому что это IO. Если это класс, он постоянно закрыт. Lazy может быть лучше.

+0

Спасибо usr, как реализовать Lazy здесь .. ?? Я мог бы лучше сделать еще одну функцию GetDictionary (string id), где он вернет словарь, чтобы сделать эту работу .. ?? – BigChief

+1

Ну, да, это было мое первое предложение. Это сработает. – usr