Async等待如何使用返回值

Ale*_*ens 19 c# async-await

我有一个我从另一个开发人员继承的Windows服务,它运行速度非常慢,并且对eBay API有很多慢速调用.我希望在没有太多重构的情况下加快速度.

我刚刚开始考虑使用c#async/await尝试使用这些慢速调用来运行异步.这就是我想要实现的目标:

我有一个非常繁忙的方法,可以进行如下调用:

getProducts
getCategories
getVehicles
getImages
Run Code Online (Sandbox Code Playgroud)

我的想法是我可以简单地将方法更改为async并添加Task<T>到返回类型,如下所示:

public async Task<String> ProcessAdditionalProductDetialsAsync(ItemType oItem)
{
    String additionalProductDetails = string.Empty;

    if (oItem.ItemSpecifics.Count > 0)
    {
        foreach (NameValueListType nvl in oItem.ItemSpecifics)
        {                  
            if (nvl.Value.Count > 0)
            {
                foreach (string s in nvl.Value)
                {
                    additionalProductDetails += "<li><strong>" + nvl.Name + ":</strong>&nbsp;" + s + "</li>";
                }
            }
        }
    }
    return additionalProductDetails;
}
Run Code Online (Sandbox Code Playgroud)

然后等待调用它们:

Task<String> additionalProductDetials = ebayPartNumbers.ProcessAdditionalProductDetialsAsync(item);
Task<PartNumberCollection> partNumberCollection = ebayPartNumbers.ProcessPartNumbersAsync(item); 


await Task.WhenAll(partNumberCollection, additionalProductDetials);
Run Code Online (Sandbox Code Playgroud)

如何获取返回的类型以便我可以使用它们?我尝试过只使用partNumberCollection但它只有await可用的属性.

Ufu*_*arı 19

在Task类上使用Result属性:

await Task.WhenAll(partNumberCollection, additionalProductDetials);

var partNumberCollectionResult = partNumberCollection.Result;
var additionalProductDetialsResult = additionalProductDetials.Result;
Run Code Online (Sandbox Code Playgroud)

  • 您应该使用`await`而不是`Result`来避免在`AggregateException`中包装异常. (5认同)

Jon*_*eet 14

如果返回的任务Task.WhenAll已完成,则表示您传递给它的所有任务也已完成.这反过来意味着您可以使用Result每个任务的属性,而不会有阻塞的风险.

string details = additionalProductDetials.Result;
Run Code Online (Sandbox Code Playgroud)

或者,您可以等待任务,以便与其他异步代码保持一致:

string details = await additionalProductDetials;
Run Code Online (Sandbox Code Playgroud)

同样,这保证不会阻止 - 如果您之后Task.WhenAll由于某种原因删除了(例如,您很高兴在获得部件号收集之前使用详细信息启动另一项任务),那么您不需要改变代码.


Moh*_*our 8

您的async方法缺乏await运算符并将同步运行.当您调用非阻塞API时,您可以使用Task.Run()在后台线程上执行cpu绑定的工作.

public async Task<String> ProcessAdditionalProductDetialsAsync(ItemType oItem)
{
    return await Task.Run(() =>
    {
        String additionalProductDetails = string.Empty;

        if (oItem.ItemSpecifics.Count > 0)
        {
            foreach (NameValueListType nvl in oItem.ItemSpecifics)
            {
                if (nvl.Value.Count > 0)
                {
                    foreach (string s in nvl.Value)
                    {
                        additionalProductDetails += "<li><strong>" + nvl.Name + ":</strong>&nbsp;" + s + "</li>";
                    }
                }
            }
        }
        return additionalProductDetails;
    });
}
Run Code Online (Sandbox Code Playgroud)

并得到结果

var detail = await ProcessAdditionalProductDetialsAsync(itemType);
var result = ProcessAdditionalProductDetialsAsync(itemType).Result;
Run Code Online (Sandbox Code Playgroud)