【问题标题】:Is there a way to run async lambda synchronously?有没有办法同步运行 async lambda?
【发布时间】:2024-07-31 15:15:02
【问题描述】:

有没有办法同步运行 async lambda?不允许修改 lambda 表达式,必须保持原样。

复制/粘贴示例(这是一个抽象):

var loopCnt = 1000000;

Action<List<int>> aslambda = async (l) =>
{
    Thread.Sleep(100);
    await Task.Run(() => { });
    for (int i = 0; i < loopCnt; i++) { l.Add(i); }
};

var lst = new List<int>();
aslambda(lst); //This runs asynchronously 
if (lst.Count < loopCnt-100) { ; }

解决方案:

真的接受一个的答案让我进退两难。我已经用 NuGet 包尝试了 Stephen Cleary 的解决方案 - 效果很好并且适用范围广泛,但是 dvorn 对问题的回答(因为它是制定的;))是容易得多。

dvorn 是否改变了 lambda 的签名?不是和是;)

来自 MSDN:

请注意,lambda 表达式本身没有类型,因为 通用类型系统没有“lambda”的内在概念 表达。”但是,有时非正式地讲话很方便 lambda 表达式的“类型”。在这些情况下,类型是指 到 lambda 表达式的委托类型或表达式类型 已转换。

因此,双方都收到 +1 并接受了 Stephen Cleary

的回答

【问题讨论】:

  • aslmbda(lst).ToList() -> 这不会停止延迟执行并在返回给您之前强制填写列表吗?
  • aslambda(..) 的返回类型为 void。
  • aslambda(lst).Wait(); ?而不是 Thread.Sleep(100); await Task.Run(()=&gt;{}); 这没有任何意义只是使用 await Task.Delay(100);
  • @m.rogalski: aslambda(..) 的返回类型是无效的!不允许修改 lambda 表达式。
  • 我不认为您可以跟踪异步 void 何时完成。我错了吗?

标签: c# multithreading lambda async-await


【解决方案1】:

有没有办法同步运行 async [void] lambda?

是的,但和所有 sync-over-async hacks 一样,它很危险,不适用于所有 lambda。

您必须有一个custom SynchronizationContext to detect the completion of an async void method(或 lambda)。这很重要,但您可以使用我的AsyncContext(在 NuGet 包中提供Nito.AsyncEx.Context):

AsyncContext.Run(() => aslambda(lst));

【讨论】:

  • 这就是我在等的人。打算自己试试这个。
  • 关键在我的SynchronizationContext article 的末尾:async void 方法会生成特殊代码以在 SyncCtx 开始和结束时通知它们。 UI SyncCtxs 只是忽略这些通知。这些通知通常只在旧版 ASP.NET WebForms 异步事件处理程序中使用,因此 ASP.NET 可以检测到处理程序何时全部完成并且响应已准备好发送到客户端。
  • 感谢您的指导。我会试试看。如果您可以发布代码示例(不包含 NuGet 包),那就太好了。
  • @Rekshino:不,代码太多。不过你可以check it out on GitHub
  • @StephenCleary 有一个更简单的方法来解决这个问题(至少按照它的公式)。
【解决方案2】:

更好的解决方案:您无法更改 lambda,但您可以更改分配给它的局部变量的类型。请注意,本机类型的异步 lambda 不是 Action 而是 Func

...
Func<List<int>, Task> aslambda = async (l) =>
...
...
aslambda(lst).Wait();
...

【讨论】:

    最近更新 更多