C# IProgress<;T>;和Parallel.ForEach同步问题
我遇到了一个同步问题,涉及在Parallel.ForEach中报告进度。我在一个控制台应用程序中重新创建了这个问题的简化版本。该示例实际上只使用列表中的一项。代码如下:C# IProgress<;T>;和Parallel.ForEach同步问题,c#,parallel-processing,parallel.foreach,iprogress,C#,Parallel Processing,Parallel.foreach,Iprogress,我遇到了一个同步问题,涉及在Parallel.ForEach中报告进度。我在一个控制台应用程序中重新创建了这个问题的简化版本。该示例实际上只使用列表中的一项。代码如下: class Program { static void Main(string[] args) { int tracker = 0; Parallel.ForEach(Enumerable.Range(1, 1), (item) => {
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);
}
}
}
类程序
{
静态void Main(字符串[]参数)
{
int-tracker=0;
Parallel.ForEach(可枚举的范围(1,1),(项)=>
{
var进度=新进度((p)=>
{
跟踪器=p;
WriteLine(String.Format(“{0}”,p));
});
测试(进度);
});
WriteLine(“最后一个值是:{0}”,tracker);
Console.ReadKey();
}
静态孔隙试验(I进度)
{
对于(int i=0;i<20;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;
}
}
类程序
{
静态void Main(字符串[]参数)
{
int-tracker=0;
Parallel.ForEach(可枚举的范围(1,1),(项)=>
{
跟踪器=测试();
});
WriteLine(“最后一个值是:{0}”,tracker);
Console.ReadKey();
}
静态int测试()
{
int i;
对于(i=0;i<20;i++)
{
Console.WriteLine(i.ToString());
}
返回i;
}
}
它的行为和我预期的一样。据我所知,Parallel.ForEach为列表中的每个in项创建了一个任务,而IProgress捕获了创建它的上下文。考虑到它是一个控制台应用程序,我认为这无关紧要。救命啊 这一解释与上面所写的内容几乎一模一样: 提供给构造函数的任何处理程序或注册了ProgressChanged事件的事件处理程序都将通过构造实例时捕获的SynchronizationContext实例调用如果在构建时没有当前SynchronizationContext,则将在线程池上调用回调。
使用
Progress.Report
可以有效地将线程池中的20个任务排入队列。无法保证它们的执行顺序。进程将在单独的线程上运行它的代码。从Test
到它的调用作为事件发送。因此,Parallel.ForEach
将在Progress
处理Test
发送给它的所有值之前完成。即使没有Parallel.ForEach
,您也会看到类似的行为。您不需要调用String.Format
。