2015-02-12 3 views
1

Странная вещь происходит здесь. Я думал, что Parallel.Foreach будет ждать, пока все его задачи будут полными, прежде чем двигаться дальше. Но, у меня есть что-то вроде этого:Должен ли Parallel.Foreach ждать?

List<string> foo(List<A> list){ 
    Dictionary<string, bool> dictionary = new Dictionary<string, bool>(); 
    Parallel.Foreach(list, element => 
    { 
     dictionary[element.Id] = true; 
     if (element.SomeMethod()){ 
      dictionary[element.Id] = false; 
     } 
    }); 

    List<string> selectedIds = (from element in list where !dictionary[element.Id] select element.Id).ToList(); 
    return selectedIds; 
} 

, а затем я получаю System.Collections.Generic.KeyNotFoundException (иногда, не всегда) в избранной линии. Как вы можете видеть, я инициализирую словарь для каждого возможного ключа (идентификаторы элементов списка), а затем получаю это исключение, что заставило меня подумать, что эта строка может быть достигнута до завершения выполнения Parallel.Foreach ... Это правильно? Если да, то как я могу дождаться завершения всех ветвей этого Parallel.Foreach?

+0

мой опыт и все пробы, которую я видел, если что основной поток блоков, пока работа будет fnished – pm100

+0

ConcurrentDictionary! – tolanj

+1

И большой пример для примера plink, который также является более читаемым – tolanj

ответ

8

Parallel.Foreach не нужно ждать, поскольку он не возвращает Task и не является асинхронным. Когда вызов этого метода завершается, итерация уже выполнена.

Однако Parallel.Foreach использует несколько потоков одновременно и Dictionary не является потокобезопасным.

У вас, вероятно, есть условия гонки на ваших руках, и вместо этого вы должны использовать поточный сейф ConcurrentDictionary.


Этот конкретный случай может быть решена более простым способом с помощью PLINQ-х AsParallel:

list.AsParallel().Where(element => !element.SomeMethod());