c# - 在异步/等待方面,常规 foreach 和 ForEach LINQ 运算符有什么区别

标签 c# linq asynchronous foreach async-await

这是相同(?)功能的三个版本

版本 1:

public async Task SomeMethodAsync(List<string> foos)
{
    foreach(var foo in foos)
    {
        await SomeOtherMethodAsync();
    }
    DoSomethingElse();
}

版本 2:

public void SomeMethod(List<string> foos)
{
    foos.ForEach(async foo => await SomeOtherMethodAsync());
    DoSomethingElse();
}

版本 3:

public async Task SomeMethod(List<string> foos)
{
    var tasks = foos.Select(foo => SomeOtherMethodAsync());
    await Task.WhenAll(tasks);
    DoSomethingElse();
}
  1. 为什么第一个版本需要将方法标记为异步才能在 foreach 循环内使用等待,而第二个版本不需要标记为异步(只是 Lambda 需要异步)。

  2. 第二个版本是否在 SomeMethod 退出之前等待循环内的所有 async/await 调用完成?我问这个是因为 SomeMethod() 不是异步的,它的调用者不会等待它。

  3. 第三个版本是否比版本 1 和 2 更受欢迎?

最佳答案

您的问题非常广泛,尤其是因为其中包含多个问题。但是,为了帮助……

  1. Why does this first version require the method to be marked async to use await inside the foreach loop vs the second version which doesn't need to be marked async (just the Lambda needs to be async).

方法必须标记为async使用 await .在您的第二个版本中,外部方法不使用 await .只有在其中声明的匿名方法才可以。该匿名方法是一个完全不同的范围,并且使用 await其中不涉及对外部方法的任何实际更改。在这方面,它们实际上是两个完全独立的方法声明。

  1. Does the second version wait for all the async/await calls inside the loop to complete before SomeMethod exits? I ask this because SomeMethod() is not async and it will not be awaited by it's caller.

第二个版本不是合法代码。没有 IList<T>.ForEach()方法。我假设您的真实代码使用 List<T>.ForEach() .考虑到这一点……

没有。您的第二个版本启动所有异步操作,然后返回。当您观察代码运行时,这应该已经很清楚了。

  1. Is the third version the preferred way over versions 1 & 2?

第三版不是合法代码。它不应该被标记为async .但是,假设您的真实代码是正确的并且没有标记为 async 的方法……

“首选”见仁见智。然而,考虑到只有第三个版本同时运行所有操作并且提供了一种等待它们全部完成的机制,这显然是三个版本中最有用的.

  1. Is it just with the ForEach LINQ operator or does the same thing happen with other LINQ operators such as Where, Select etc?

(没有“ForEach LINQ 运算符”……见上文。)

“同样的事情”会发生吗?这完全取决于您如何使用它们。您已经有一个使用 Select() 的示例(您的第三个) , 并且工作方式不同。所以从这个意义上说,显然 “同样的事情” 不会发生。但在所有异步操作一起启动并且枚举可以在这些操作完成之前完成的意义上是相同的。

另一方面,ForEach()方法是同步和即时的,而 LINQ 方法使用延迟执行。也就是说,它们创建了一个枚举对象,但在您实际使用该对象之前不会发生实际的枚举。

所以在你的第二个例子中,操作都是在 ForEach() 时开始的。方法返回。但在第三个示例中,它们直到您调用 WaitAll() 才开始。该方法枚举了您使用 Select() 创建的投影.

短语“同一件事” 没有明确定义,可能表示多种意思。如您所见,它在某些方面“相同”,而在其他方面“相同”

关于c# - 在异步/等待方面,常规 foreach 和 ForEach LINQ 运算符有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45384963/

相关文章:

c# - 从 ASP.Net MVC5 调用的单独类库 .dll 中的 Hangfire

c# - "The LINQ expression node type ' 调用 ' is not supported in LINQ to Entities"- 难倒了!

c# - 如何在已编译的表达式树中调试或设置 break 语句?

javascript - 当你可以在 Javascript 中全局调用函数时,为什么要使用回调呢?

c# - 将 IoC/DI 容器与运行时相关的构造函数参数一起使用

c# - 检查是否可以建立与数据库的连接

c# - Visual Studio 2012 Fakes - 如何验证调用的方法?

c# - LINQ 加入多个 From 子句

multithreading - 有关异步IO调用的更多详细信息

node.js - 多次调用相同的函数并处理合并的结果集