c# - Lambda 表达式、捕获的变量和线程

标签 c# .net multithreading lambda

我知道 .NET lambda 表达式可以捕获外部变量。 但是,我已经多次看到变量作为参数显式传递给 lambda 表达式,并且 .NET 库似乎也支持这种情况(例如 ThreadPool.QueueUserWorkItem)。

我的问题是这些捕获的限制是什么?实际在与创建它们的线程不同的线程上执行的 lambda(例如 ThreadPool.QueueUserWorkItem 或 Thread)或充当回调(即稍后调用)的 lambda 怎么样?

一般来说,什么时候应该依赖捕获变量,什么时候使用显式参数?例如:

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
}

谢谢!

更新:修复了第二个 ThreadPool.QueueUserWorkItem 示例。

最佳答案

我认为在你的第一个例子中,你的意思是

QueueUserWorkItem( () => SendMessage(message) );

在你的第二项中,参数s是从哪里来的?我想你的意思是

QueueUserWorkItem( s => {SendMessage((string)s);} , message );

现在,这两个功能等效,但是

  • 第一种情况:参数 message 从范围复制 此 DoStuff 方法并存储 直接在你的 lambda 表达式中 本身,作为一个闭包。 lambda 有 保留一份 message 的副本。

  • 第二种情况:发送messageQueue,队列保持 持有它(连同 lambda), 直到调用 lambda。这是 在运行时通过 lambda,到 lambda。

我认为第二种情况在编程上更灵活,因为它理论上允许您稍后在调用 lambda 之前更改 message 参数的值。然而,第一种方法更容易阅读并且更不易产生副作用。但在实践中,两者都有效。

关于c# - Lambda 表达式、捕获的变量和线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3900036/

相关文章:

c# - AWS 的奇怪版本控制问题

C# 将十六进制字符串发送到 tcp 套接字

c# - URL 编码后,数字 1 随机附加到我的 JWT key 的末尾

c# - AWS/SES 电子邮件发送...您的体验如何?

multithreading - Perl 线程中断 sleep 不起作用

c# - 更改 UltraWinGrid 列的顺序

c# - System.Security.Principal.WindowsIdentity 的这种使用是否合理安全?

c# - 公共(public)十进制属性线程安全吗?

c++ - 它怎么可能成为竞争条件。或者我的代码有问题

ios - 主队列上的 dispatch_async block 永远不会执行