Shd*_*dNx 7 .net c# lambda multithreading
我知道.NET lambda表达式可以捕获外部变量.但是,我已经很多次看到变量作为参数显式传递给lambda表达式,而.NET库似乎也支持它(例如ThreadPool.QueueUserWorkItem).
我的问题是这些捕获的局限性是什么?如果lambda实际上是在与创建它们的线程不同的线程上执行的(例如ThreadPool.QueueUserWorkItem或Thread),或者作为回调的lambas(即稍后调用)?
一般来说,何时应该依赖捕获的变量,何时使用显式参数?例如:
public void DoStuff()
{
string message = GetMessage();
ThreadPool.QueueUserWorkItem(s => SendMessage(message)); // use captured variable
// -- OR --
ThreadPool.QueueUserWorkItem(s =>
{
string msg = (string)s;
SendMessage(msg);
}, message); // use explicit parameter
}
Run Code Online (Sandbox Code Playgroud)
谢谢!
更新:修复了第二个ThreadPool.QueueUserWorkItem示例.
我想在你的第一个例子中,你的意思是
QueueUserWorkItem( () => SendMessage(message) );
Run Code Online (Sandbox Code Playgroud)
在你的第二个项目中,参数s
来自哪里?我想你的意思是
QueueUserWorkItem( s => {SendMessage((string)s);} , message );
Run Code Online (Sandbox Code Playgroud)
现在,这两个都是等效的,但是
在第一种情况下:参数
message
从此DoStuff
方法的范围复制并直接存储在lambda表达式本身中,作为闭包.lambda保留了副本message
.
在第二种情况下:message
发送到Queue
,并且队列保持它(与lambda一起),直到lambda被调用.它在运行lambda时传递给lambda.
我认为第二种情况在程序上更灵活,因为它理论上可以允许您message
在调用lambda之前更改参数的值.然而,第一种方法更容易阅读,并且对副作用更具免疫力.但在实践中,两者都有效.
对于您的示例(对不可变字符串对象的引用),它绝对没有区别.
一般而言,制作参考文献的副本并不会产生太大的影响.使用值类型时,它很重要:
double value = 0.1;
ThreadPool.QueueUserWorkItem( () => value = Process(value)); // use captured variable
// -- OR --
ThreadPool.QueueUserWorkItem( () =>
{
double val = value; // use explicit parameter
val = Process(val); // value is not changed
});
// -- OR --
ThreadPool.QueueUserWorkItem( (v) =>
{
double val = (double)v; // explicit var for casting
val = Process(val); // value is not changed
}, value);
Run Code Online (Sandbox Code Playgroud)
第一个版本不是线程安全的,第二个和第三个版本可能是.
最后一个版本使用object state
参数,即Fx2(pre-LINQ)功能.
归档时间: |
|
查看次数: |
3255 次 |
最近记录: |