IProgress<T> и Parallel.ForEach Проблемы с синхронизацией
Я сталкиваюсь с проблемой синхронизации, связанной с сообщением о прогрессе внутри Parallel.ForEach. Я воссоздал упрощенную версию проблемы в консольном приложении. Пример на самом деле использует только один элемент в списке. Вот код:
class Program
{
static void Main(string[] args)
{
int tracker = 0;
Parallel.ForEach(Enumerable.Range(1, 1), (item) =>
{
var progress = new Progress<int>((p) =>
{
tracker = p;
Console.WriteLine(String.Format("{0}", p));
});
Test(progress);
});
Console.WriteLine("The last value is: {0}", tracker);
Console.ReadKey();
}
static void Test(IProgress<int> progress)
{
for (int i = 0; i < 20; i++)
{
progress.Report(i);
}
}
}
Как вы можете видеть, строка, которую я ожидаю увидеть последней, не выводится последней и не содержит 20. Но если я удаляю отчеты о ходе выполнения и просто записываю данные в цикл for следующим образом:
class Program
{
static void Main(string[] args)
{
int tracker = 0;
Parallel.ForEach(Enumerable.Range(1, 1), (item) =>
{
tracker = Test();
});
Console.WriteLine("The last value is: {0}", tracker);
Console.ReadKey();
}
static int Test()
{
int i;
for ( i = 0; i < 20; i++)
{
Console.WriteLine(i.ToString());
}
return i;
}
}
ведет себя как я ожидаю. Насколько я знаю, Parallel.ForEach создает задачу для каждого элемента в списке, а IProgress фиксирует контекст, в котором он создан. Учитывая, что это консольное приложение, я не думаю, что это будет иметь значение. Помогите, пожалуйста!
1 ответ
Объяснение в значительной степени именно то, что написано в документации:
Любой обработчик, предоставленный конструктору или обработчикам событий, зарегистрированным в событии ProgressChanged, вызывается через экземпляр SynchronizationContext, захваченный при его создании. Если во время создания нет текущего SynchronizationContext, обратные вызовы будут вызываться в ThreadPool.
Используя Progress<T>.Report
вы фактически ставите в очередь 20 задач в пуле потоков. Там нет никакой гарантии относительно того, в каком порядке они выполнены.