IProgress<T> 和 Parallel.ForEach 同步问题
IProgress<T> and Parallel.ForEach Sync Issues
我 运行 遇到一个同步问题,涉及在 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 捕获创建它的上下文。鉴于它是一个控制台应用程序,我认为这无关紧要。请帮忙!
解释与the docs中所写的几乎完全相同:
Any handler provided to the constructor or event handlers registered with the ProgressChanged event are invoked through a SynchronizationContext instance captured when the instance is constructed. If there is no current SynchronizationContext at the time of construction, the callbacks will be invoked on the ThreadPool.
通过使用 Progress<T>.Report
,您可以有效地在线程池中排队 20 个任务。无法保证它们的执行顺序。
我 运行 遇到一个同步问题,涉及在 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 捕获创建它的上下文。鉴于它是一个控制台应用程序,我认为这无关紧要。请帮忙!
解释与the docs中所写的几乎完全相同:
Any handler provided to the constructor or event handlers registered with the ProgressChanged event are invoked through a SynchronizationContext instance captured when the instance is constructed. If there is no current SynchronizationContext at the time of construction, the callbacks will be invoked on the ThreadPool.
通过使用 Progress<T>.Report
,您可以有效地在线程池中排队 20 个任务。无法保证它们的执行顺序。