Async await how to use return values

百般思念 提交于 2019-12-31 13:28:22

问题


I have a windows service that I have inherited from another developer, it runs very slow and has numerous slow call to the eBay API. I wish to speed it up without too much refactoring.

I've just started to look at using c# async/await to try to get some of these slow call to run async. Here's what i'm trying to achieve:

I have a 1 very busy method that makes lots of calls as below:

getProducts
getCategories
getVehicles
getImages

My thoughts were that I could simply change the methods to async and add Task<T> to the return type as below:

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;
}

Then call them with await:

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


await Task.WhenAll(partNumberCollection, additionalProductDetials);

How do I get hold of the returned types so I can use them? I have tried just using partNumberCollection but it only has the await properties available.


回答1:


Use Result property on Task class:

await Task.WhenAll(partNumberCollection, additionalProductDetials);

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



回答2:


If the task returned by Task.WhenAll has completed, that means all of the tasks that you passed to it have completed too. That in turn means that you can use the Result property of each task, with no risk of it blocking.

string details = additionalProductDetials.Result;

Alternatively, you could await the tasks, for consistency with other async code:

string details = await additionalProductDetials;

Again, this is guaranteed not to block - and if you later remove the Task.WhenAll for some reason (e.g. you're happy to use the details to kick off another task before you've got the part number collection) then you don't need to change the code.




回答3:


Your async method lacks of await operators and will run synchronously. while you are calling non blocking API you could use Task.Run() to do cpu-bound work on background thread.

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;
    });
}

and get result

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



回答4:


Try this code:

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;
 }

Usage:

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

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


来源:https://stackoverflow.com/questions/26510094/async-await-how-to-use-return-values

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!