【问题标题】:Using TAP with IEnumerable<>将 TAP 与 IEnumerable<> 一起使用
【发布时间】:2022-01-07 20:29:08
【问题描述】:

我正在更新我的代码以异步运行,但我遇到了问题,因为我正在使用 List 和 IEnumerable 类型。我所做的一切都给了我同样的错误:你不能等待列表或 IEnumerable 不包含 GetAwaiter 的定义。

考虑以下代码:

var salesTask = GetSalesOpportunitiesAsync();

var opportunityTasks = new List<Task>
{
   salesTask // I've excluded the other tasks for this snippet.
};
    
while (opportunityTasks.Count > 0)
{
    Task finishedTask = await WhenAny(opportunityTasks);
    opportunityTasks.Remove(finishedTask);
}

private async Task GetSalesOpportunitiesAsync()
{
    _sales = await (from opportunity in _opportunities
                   where opportunity.Stage.Name is "Prospect" or "Lead" or "Qualified"
                   select opportunity).ToList();
}

好像我读到的所有东西都只是稍微触及了我需要的东西,但从来没有完全让我找到解决方案。对于我正在进行的项目,我们从 API 中引入了超过 1.7K 复杂对象的非常大的列表。然后,我们在 UI 上对该列表进行多次排序,以创建动态看板显示。目标是遍历这个庞大的列表并异步分解成更小的列表,因此 HTML 中的循环不需要做太多工作。

更新:包含 Api 调用 服务类中的实际 API 调用。:

public List<Opportunity> GetOpportunities()
{
    {
        OpportunitiesApi opportunitiesApi = new (_connection.CwConfiguration);

        List<Opportunity> opportunities = new ();
        int               pageNumber    = 0;
        bool              areAvailable  = false;

        while (areAvailable == false)
        {
            List<Opportunity> opportunityPage       = opportunitiesApi.GetSalesOpportunities(_settings.ClientId, null, null, null, null, null, pageNumber);
            int               opportunityCount      = opportunityPage.Count;
            if (opportunityCount == 0) areAvailable = true;
            opportunities.AddRange(opportunityPage);
            pageNumber++;
        }

        return opportunities;
    }
}

public async Task<List<Opportunity>> GetOpportunitiesAsync()
{
    List<Opportunity> opportunities = await Task.Run(GetOpportunities);

    return new List<Opportunity>(opportunities);
}

我们如何调用剃须刀组件:

protected override async Task OnInitializedAsync()
{
    _opportunities = await _opportunityService.GetOpportunitiesAsync();
}

【问题讨论】:

  • 什么是_opportunities? GetSalesOpportunitiesAsync 似乎缺少返回语句。 WhenAny 上的循环与仅使用 WhenAll 的循环相比,我也有点困惑
  • 假设_opportunities是外部数据库,则可以将ToList()改为ToListAsync()
  • @Gabriel 我感觉不是;我认为不能在例如 EF Where 中使用像 string is "x" or "y" 这样的模式匹配表达式(“表达式树可能不包含 is 模式匹配运算符”.. 但无法检查 atm ?)
  • _opportunities 是我们调用的 API 提供给我们的机会类型列表。我已经尝试添加 ToListAsync() 但由于某种原因,我无法在剃须刀组件中访问它。
  • 向我们展示 API 调用;那可能是异步的。但老实说,如果您期望能够等待某些东西,并且处理内存中已有的数据块会大大提高性能,我想您可能会失望..

标签: c# asp.net-core async-await ienumerable blazor-server-side


【解决方案1】:

我认为您误解了异步代码的目的。它仅在从外部源获取数据时有用:网络请求、文件系统等。这样线程就可以在等待响应的同时做其他工作,而不是无所事事。在 ASP.NET 的上下文中,这意味着您的应用程序可以使用更少的线程来处理更高负载的 HTTP 请求。

如果数据已经在内存中,则无需等待,因此不需要异步代码。

因此,如果_opportunities 已将数据保存在内存中,那么您不需要异步代码来访问该数据。

但是,从 API 获取数据的代码可以是异步的。

Asynchronous programming with async and await 上的 Microsoft 文档提供了非常丰富的信息。我建议你通读这些文章。

【讨论】:

  • 这两天我什么也没做,只是通读了微软的异步编程文档。当我读到它时,这一切都是有道理的。但是当我真正尝试使用它时,我遇到了意想不到的问题。
  • @JustinErdmier 您实际上从外部源获取数据的代码是什么?我怀疑它在opportunitiesApi.GetSalesOpportunities()。那是你的代码还是一些外部库?有opportunitiesApi.GetSalesOpportunitiesAsync()吗?
  • 另外,我知道 _opportunities 中的数据已经在内存中。我想要实现的是提高通过该数据进行额外循环的性能。就目前而言,当您导航到页面时,它会在准备数据和构建视图时提供 15-30 秒的空白屏幕。我知道 Blazor 就是为此而生的,所以我想尝试让它更快。
  • 我已经用实际调用 API 的服务类中的代码更新了帖子。
  • @JustinErdmier 对,我看到了。这就是我要问的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多