Async等待如何使用返回值

时间:2014-10-22 14:36:20

标签: c# async-await

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

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

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

getProducts
getCategories
getVehicles
getImages

我的想法是,我只需将方法更改为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;
}

然后等待:

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


await Task.WhenAll(partNumberCollection, additionalProductDetials);

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

4 个答案:

答案 0 :(得分:19)

在Task类上使用Result属性:

await Task.WhenAll(partNumberCollection, additionalProductDetials);

var partNumberCollectionResult = partNumberCollection.Result;
var additionalProductDetialsResult = additionalProductDetials.Result;

答案 1 :(得分:14)

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

string details = additionalProductDetials.Result;

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

string details = await additionalProductDetials;

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

答案 2 :(得分: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;
    });
}

并获得结果

var detail = await ProcessAdditionalProductDetialsAsync(itemType);
var result = ProcessAdditionalProductDetialsAsync(itemType).Result;

答案 3 :(得分:0)

试试这段代码:

public async Task<String> ProcessAdditionalProductDetialsAsync(ItemType oItem) { 
    String additionalProductDetails = await Task.Run(() => {
       if (oItem.ItemSpecifics.Count > 0) {
          foreach (NameValueListType nvl in oItem.ItemSpecifics) { 
             if (nvl.Value.Count > 0) {
                 string retval = String.Empty;

                 foreach (string s in nvl.Value) {
                     retval += "<li><strong>" 
                       + nvl.Name + ":</strong>&nbsp;" + s + "</li>";
                 }
             }
          }
       }
       return retval;
     }
     return additionalProductDetails;
 }

用法:

private async void GetAdditionalProductDetailsAsync(Action<string> callback) {
   string apd = await ProcessAdditionalProductDetialsAsync();
   callback(apd);
}

private void AdditionalProductDetailsRetrieved(string apd) {
    // do anything with apd
}