是否可以在委托给具有相同返回类型的任务的分支中避免“返回等待”?

问题描述 投票:0回答:1

我有一个异步方法来处理聚合请求。它基本上将请求分解为单个请求,由具有相同返回类型的另一种方法处理,并将答案组合成单个响应。如果聚合请求实际上仅包含单个请求,我可以直接委托给第二种方法。

当我这样做时,由于我的方法是

async
,我无法直接从其他方法返回
Task<string>
,我需要
await
它,即使我的方法对结果没有做任何事情。另一方面,在聚合响应的分支中,我确实需要获取结果才能生成聚合响应,因此我确实需要
await

必须使用

return await
对我来说似乎不自然,并且似乎剥夺了调用者进行自己优化的机会。

我的问题是:

  1. 是否可以/建议在委托给具有相同返回类型的

    return await
    的分支中避免使用
    Task
    ?例如,不使用方法
    async
    ,并使用
    Task
    ?
     在第二个分支中等待 
    task.GetAwaiter().GetResult()

  2. 或者我不应该担心它,因为调用者的最终结果永远不会有任何明显的差异?

最终还是要等待结果。

这个例子已经被简化为使用简单的字符串操作来演示这个想法;实际上我的方法要复杂得多。

public async Task<string> ProcessCombinedRequest(List<string> requestList)
{
    if (requestList.Count == 1)
    {
        return await ProcessSingleRequest(requestList[0]);
    }

    // Start all the sub-tasks concurrently
    var taskList = new List<Task<string>>();
    foreach (string request in requestList)
    {
        taskList.Add(ProcessSingleRequest(request));
    }

    // Wait for each of them to finish and get their results
    var aggregatedResponse = new StringBuilder();
    foreach (var task in taskList)
    {
        string singleResponse = await task;
        aggregatedResponse.AppendLine(singleResponse);
    }
    return aggregatedResponse.ToString();
}

private async Task<string> ProcessSingleRequest(string request)
{
    // Long running operation
    Thread.Sleep(4000);
    return request + " was processed.";
}
c# async-await
1个回答
0
投票

是的,但有一些注意事项和细微差别。您可以使用非

async
方法:

public Task<string> ProcessCombinedRequest(List<string> requestList)
{
    // TODO: consider ternary conditional or switch expression, lambda, etc
    // TODO: consider the empty list case?
    if (requestList.Count == 1)
    {
        return ProcessSingleRequest(requestList[0]);
    }
    return ProcessCombinedRequestMulti(requestList);
}
private async Task<string> ProcessCombinedRequestMulti(List<string> requestList)
{
    // Start all the sub-tasks concurrently
    var taskList = new List<Task<string>>();
    // .. etc as before
}

这消除了一层状态机开销,但是重要的是,它还改变了异常情况下的行为 - 例如,如果

requestList
结果是
null
,或者发生了一些其他随机错误 - 而不是返回错误的
Task<string>
,您的方法可能
throw
- 在任何一种情况下,观察到的堆栈跟踪都可能略有不同。

如果您确信不存在这种风险(也许进行一些

Debug.Assert
检查等),
async
版本可能非常常见,性能很重要:这是你当然可以考虑的事情。但是,如果您对影响没有信心:也许不用担心......

举一个具体的例子:https://github.com/dotnet/runtime/blob/ea9d53e694671ca8c70d61eb1df8779959045af6/src/libraries/Microsoft.Extensions.Caching.Abstractions/src/Hybrid/HybridCache.cs#L74-L82

© www.soinside.com 2019 - 2024. All rights reserved.