Erw*_*yer 16 c# lambda closures asynchronous task-parallel-library
我刚刚遇到以下行为:
for (var i = 0; i < 50; ++i) {
Task.Factory.StartNew(() => {
Debug.Print("Error: " + i.ToString());
});
}
Run Code Online (Sandbox Code Playgroud)
将导致一系列"错误:x",其中大多数x等于50.
同理:
var a = "Before";
var task = new Task(() => Debug.Print("Using value: " + a));
a = "After";
task.Start();
Run Code Online (Sandbox Code Playgroud)
将导致"使用价值:之后".
这显然意味着lambda表达式中的串联不会立即发生.在声明表达式时,如何在lambda表达式中使用外部变量的副本?以下内容不会更好(我承认这不一定是不连贯的):
var a = "Before";
var task = new Task(() => {
var a2 = a;
Debug.Print("Using value: " + a2);
});
a = "After";
task.Start();
Run Code Online (Sandbox Code Playgroud)
Pan*_*vos 26
这与lambdas有关,而不是线程.lambda捕获对变量的引用,而不是变量的值.这意味着,当您尝试使用我在你的代码,它的价值将是任何存储在我持续.
为避免这种情况,您应该在lambda启动时将变量的值复制到局部变量.问题是,启动任务有开销,第一个副本可能只在循环结束后执行.以下代码也将失败
for (var i = 0; i < 50; ++i) {
Task.Factory.StartNew(() => {
var i1=i;
Debug.Print("Error: " + i1.ToString());
});
}
Run Code Online (Sandbox Code Playgroud)
正如James Manning所说,你可以在循环中添加一个局部变量并在那里复制循环变量.这样您就可以创建50个不同的变量来保存循环变量的值,但至少可以得到预期的结果.问题是,你确实得到了很多额外的分配.
for (var i = 0; i < 50; ++i) {
var i1=i;
Task.Factory.StartNew(() => {
Debug.Print("Error: " + i1.ToString());
});
}
Run Code Online (Sandbox Code Playgroud)
最好的解决方案是将loop参数作为状态参数传递:
for (var i = 0; i < 50; ++i) {
Task.Factory.StartNew(o => {
var i1=(int)o;
Debug.Print("Error: " + i1.ToString());
}, i);
}
Run Code Online (Sandbox Code Playgroud)
使用状态参数可以减少分配.查看反编译代码:
| 归档时间: |
|
| 查看次数: |
12283 次 |
| 最近记录: |