作为异步函数调用返回IEnumerable

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了作为异步函数调用返回IEnumerable相关的知识,希望对你有一定的参考价值。

我有一个获取一系列项目的函数:

List<MyType> GetPage(int pageNr) {...}

要获得所有可用的项目,您可以执行以下操作:

IEnumerable<MyType> FetchMyItems()
{
    int pageNr = 0;
    var fetchedItems = GetPage(pageNr);
    while (fetchedItems.Any()
    {   // there are items to return
        // yield return the fetched items: 
        foreach (var fetchedItem in fetchedItems)
            yield return fetchedItems;

        // get the next page
         ++pageNr;
         fetchedItems = GetPage(pageNr)
    }
}

使用此方法,我的用户将不再需要每页获取项目,如果他们只需要几个项目,则只会获取第一页。当需要更多项目时,将自动获取更多页面。缺点当然是我有时会获取一些不会被使用的项目。

我想要一个异步版本

所以我有以下GetPage:

async Task<List<MyType>> GetPageAsync(int pageNr) {...}

根据我从IEnumerable的理解,它不会创建结果序列,它只会创建枚举此序列的可能性。

这个枚举是使用'foreach'显式完成的,或隐式使用LINQ函数,如'ToList','ToArray',还有'FirstOrDefault','Any',Sum等函数。

var fetchItemTasks = FetchMyItemsAsync();
foreach (var fetchItemTask in fetchedItemTasks)
{
      MyType fetchedItem = await fetchItemTask;
      Process(fetchedItem);
}

或者,如果你做这个低级别:

var myitemsEnumerable = fetchMyItemsAsync();
// don't await yet, only create the possibility to enumerate

var enumerator = myItemsEnumerable.GetEnumerator();
while (enumerator.MoveNext())
{   // there is an item available in current:
    Task<MyType> task = enumerator.Current;
    return task;
}

看看这个,似乎函数不应该返回Task<IEnumerable<MyType>>而是IEnumerable<Task<MyType>>,如果你想访问一个你必须等待的元素。

因此,返回枚举可等待项的可能性的函数本身并不是异步的。您没有等待可枚举,可以在不访问数据库等慢速提供程序的情况下创建此可枚举。可枚举序列中的项目是等待的:

IEnumerable<Task<MyType>> FetchMyItems()
{
    int pageNr = 0;
    Task<List<MyType>> fetchItemTask = GetPageAsync(pageNr);

现在?如果我await fetchItemTask,这些物品已经在当地没有任何东西需要等待了。如果我fetchItemTask.Wait(),功能块。

答案

您的async / await模式的实现看起来不正确。

GetPageAsync签名没问题:

async Task<List<MyType>> GetPageAsync(int pageNr) {...}

现在,如果要异步调用此方法,则必须使用await关键字,该关键字将挂起执行方法并将控制权返回给其调用方,直到GetPageAsync结果准备就绪:

List<MyType> items = await GetPageAsync(pageNr);

要么

Task<List<MyType>> getPageTask = GetPageAsync(pageNr);

// Some other stuff

List<MyType> items = await getPageTask;

但请注意,await关键字只能在本身async的方法中使用。

可能我没有意识到你的应用程序异步模型的整个想法,但无论如何,我建议首先看一下这个MSDN article on asynchronous programming with async/await

以上是关于作为异步函数调用返回IEnumerable的主要内容,如果未能解决你的问题,请参考以下文章

Spring boot:使用异步方法作为同步方法

等待异步函数调用完成

如何在异步函数中调用 redux 调度作为函数体?

只有在 SwiftUI 和 Firebase 中完成循环中的异步调用时,如何才能返回函数?

异步 Lambda 函数:返回 promise 或发送 responseURL 不会终止 CloudFormation 自定义资源调用

C#中异步方法的返回类型