【问题标题】:C# - Async method in SELECT LINQ operationC# - SELECT LINQ 操作中的异步方法
【发布时间】:2019-12-12 17:27:02
【问题描述】:

让我们考虑一下这段代码:

var tasks = actionItems.Select(t => DoSmthAsync());
var resultAll = await Task.WhenAll(tasks);

和方法:

public async Task<int> DoSmthAsync()
{
    Debug.WriteLine("Threadid=" + Thread.CurrentThread.ManagedThreadId);
    var result = await DoSmthAnotherAsync();
    Debug.WriteLine("ThreadId=" + Thread.CurrentThread.ManagedThreadId);
    return result;
}

我希望这将在不同的线程中并行执行,但我看到它在同一个线程中工作。另外,我不明白任务何时运行?

【问题讨论】:

  • 嗨,异步并不意味着并行,所以期望使用不同的线程是不正确的。见stackoverflow.com/questions/14099520/…
  • 你能把DoSmthAnotherAsync的代码贴出来吗?
  • 这是什么应用程序?控制台应用程序? Windows 窗体?
  • 更大的问题是你为什么关心使用异步的线程?异步减少线程使用。

标签: c# linq asynchronous parallel-processing async-await


【解决方案1】:

您将async await 模型与并行编程混淆了。

Select 将连续迭代您的actionItems。当您等待 DoSmthAnotherAsync 时,DoSmthAsync 将控制权返回给调用者(在本例中为 Select 迭代器),因此您将获得在一个线程上创建的 Task&lt;int&gt; 列表。

要并行运行Select 语句,您需要使用PLINQ

var tasks = actionItems.AsParallel().Select(t => DoSmthAsync());

这将产生您预期的结果。

然后您需要await Task.WhenAll(tasks); 等待任务结果。然后,您可以使用各自的 Result 属性访问 tasks 列表中每个 Task&lt;int&gt; 的结果。

【讨论】:

  • AsParallel 只会并行启动任务。 OP 可能对任务从开始到完成的整个执行过程感兴趣。
  • 他的优先级似乎是计算发生在多个线程上。我已经编辑了我的帖子以包含一种检索任务结果的方法。
【解决方案2】:

另外,我不明白任务何时运行?

Task 通常在创建时启动(在这种情况下,它被称为 hot 任务)。异步方法和几乎所有内置 API 都会返回热任务。可以通过使用Task constructor(创建一个所谓的 任务)创建一个未启动的Task,但这是不常见的,不推荐。

此构造函数只应在需要将任务的创建和启动分开的高级场景中使用。

var tasks = actionItems.Select(t => DoSmthAsync());

这行代码不会创建任何任务,因此此时没有启动任何任务。 Select LINQ 方法返回延迟的可枚举,而不是具体化的集合。当您调用方法 Task.WhenAll(tasks) 时,任务的实际实现发生。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-03
    • 2016-05-02
    • 1970-01-01
    • 2023-03-16
    • 2017-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多