等待一个任务列表而不阻塞另一个任务列表

Await a task list without blocking another task list

我正在编写一段代码,从一个来源获取数据,进行一些处理,然后将其保存到另一个来源。由于两端的延迟很高,我正在尝试使用 async/await 来等待加载和保存操作完成。理想情况下,这将启动所有输入任务,并且当每个输入任务完成时,它会进行一些快速处理,然后启动输出任务 - 使用 Task.WaitAll 会导致程序在新任务开始时什么都不做。

由于第二个异步任务依赖于第一个异步任务的结果,所以我不知道如何处理第二个等待,让它恢复处理第一个等待的其他结果——一旦结果是处理并命中第二个 await 时,它会完全阻塞,直到完成保存功能,而不是继续处理其他结果。我正在尝试这样的事情,我做错了什么?

async Task MainAsync()
{
    /* gets a list of id's */

    var dataRequests = ids.Select(id => LoadEntryById(id)).ToList();

    foreach(var request in dataRequests)
    {
        RawEntry response = await request;

        ProcessedEntry result = doSomething(response);

        await SaveResult(result);
    }
}

async Task<RawEntry> LoadEntryById(int id)
{
    /* IO task */
}

async Task SaveResult(ProcessedEntry result)
{
    /* IO task */
}

不要等待单一方法,而是使用延续创建 List<Task>,然后使用 Task.WhenAll:

var tasks = ids.Select(async id => {
    var response = await LoadEntryById(id);
    var result = doSomething(response);
    await SaveResult(result);
}).ToList();

await Task.WhenAll(tasks);

这将以异步方式处理您的所有任务。

如果我理解正确的话,你可以试试这个:

Parallel.Foreach( ids.Select(id => LoadEntryById(id)), (rawEntry) => {
    var result = doSomething(rawEntry);

    await SaveResult(result);
}

RawEntry LoadEntryById(int id)
{
    /* IO task */
}

async Task SaveResult(ProcessedEntry result)
{
    /* IO task */
}

在此设置中 LoadEntryById 不需要 return 任务,但这取决于它在做什么。