我已经阅读了许多关于访问修改后的闭包的问题,所以我理解了基本原理。不过,我无法告诉 - Parallel.ForEach
是否有同样的问题?
以下面的代码片段为例,重新计算上周用户的使用情况统计数据:
var startTime = DateTime.Now;
var endTime = DateTime.Now.AddHours(6);
for (var i = 0; i < 7; i++)
{
// this next line gives me "Access To Modified Closure"
Parallel.ForEach(allUsers, user => UpdateUsageStats(user, startTime, endTime));
// move back a day and continue the process
startTime = startTime.AddDays(-1);
endTime = endTime.AddDays(-1);
}
根据我对此代码的了解,foreach
应该立即运行我的UpdateUsageStats
例程,并且开始/结束时间变量不会被更新,直到循环的下一次。这是正确的还是我应该使用局部变量来确保没有问题?
答案 0 :(得分:4)
您 访问已修改的闭包,因此它确实适用。 但是,您在使用它时不会更改其值,因此假设您没有更改UpdateUsageStats
中的值,则此处不会出现问题。
Parallel.Foreach
等待执行结束,然后才更改startTime
和endTime
中的值。
答案 1 :(得分:2)
“访问修改后的闭包”只会在捕获范围离开捕获发生的循环并在其他地方使用时导致问题。例如,
var list = new List<Action>();
for (var i = 0; i < 7; i++)
{
list.Add(() => Console.WriteLine(i));
}
list.ForEach(a => a()); // prints "7" 7 times, because `i` was captured inside the loop
在你的情况下,执行捕获的lamda不会离开循环(Parallel.ForEach
调用在循环内完全执行,每次都在。)
您仍然会收到警告,因为编译器不知道Parallel.ForEach
是否导致存储lambda以供以后调用。由于我们知道的不仅仅是编译器,我们可以放心地忽略警告。