简体   繁体   English

异步写入 IAsyncEnumerable

[英]Asynchronously write to an IAsyncEnumerable

I am using IAsyncEnumerable to return paginated results from an API as they come in, as follows:我正在使用IAsyncEnumerable从 API 返回分页结果,如下所示:

public async IAsyncEnumerable<ApiObject> GetResults(){
  int startIndex = 0;
  PaginatedResponse<ApiObject> response;
  do {
    response = await _client.GetResults(_endpoint, startIndex, _pageSize);
    foreach (var obj in response.Items){
      yield return obj;
    }
    startIndex = response.StartIndex + response.Count;
  } while (response.StartIndex + response.Count < response.Total);
}

What I want is to send requests for multiple pages in parallel, and return each page to the IAsyncEnumerable as it comes in. Order does not matter.我想要的是并行发送多个页面的请求,并将每个页面返回给IAsyncEnumerable 。顺序无关紧要。

Is what I'm attempting to do possible?我正在尝试做的事情可能吗? Can I have multiple asynchronous Tasks writing to the same IAsyncEnumerable that my method is returning?我可以让多个异步任务写入我的方法返回的同一个IAsyncEnumerable吗? The best I can come up with is to have the tasks write to a common IList , then after all tasks complete, iterate over that IList and return all elements:我能想到的最好的办法是让任务写入一个通用的IList ,然后在所有任务完成后,遍历该 IList 并返回所有元素:

public async Task<IAsyncEnumerable<ApiObject>> GetResults(){
  int totalPages = _client.MagicGetTotalPagesMethod();
  IList<ApiObject> results = new List<ApiObject>();
  var tasks = Enumerable.Range(0,totalPages).Select(async x => {
    // my goal is to somehow return from here, rather than aggregating into the IList and returning after all tasks are done
    results.AddRange(await _client.GetResults(_endpoint, x*_pageSize, _pageSize));
  });
  await Task.WhenAll(tasks);
  foreach (var result in results){
    yield return result;
  }
}

This partially solves the problem by having multiple requests out at once, but we still have to wait for all of them to return before the consumer of this GetResults can use the results.这通过一次发出多个请求部分解决了问题,但我们仍然必须等待所有请求都返回,然后此GetResults的使用者才能使用结果。

You can use the ability to order a sequence of tasks by completion to make such a method quite simple.您可以使用通过完成对一系列任务进行排序的能力来使这种方法变得非常简单。

var tasks = Enumerable.Range(0,totalPages).Select(x =>
    client.GetResults(_endpoint, x*_pageSize, _pageSize));

foreach(var task in tasks.Order())
    foreach(var item in await task)
        yield return item;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM