2014-10-22 12 views
14

Ich habe einen Windows-Dienst, den ich von einem anderen Entwickler geerbt habe, läuft es sehr langsam und hat zahlreiche langsame Aufruf an die eBay-API. Ich möchte es beschleunigen ohne zu viel Refactoring.Async erwarten, wie die Rückgabewerte

Ich habe gerade angefangen, mit C# async/await zu versuchen, einige dieser langsamen Aufruf async ausführen zu bekommen. Hier ist, was ich versuche zu erreichen:

Ich habe eine 1 sehr beschäftigt Methode, wie unten viele Anrufe macht:

getProducts 
getCategories 
getVehicles 
getImages 

Meine Gedanken waren, dass ich einfach die Methoden async ändern könnte und fügen wie unten Task<T> zum Rückgabetyp:

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

Dann rufen sie mit await:

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


await Task.WhenAll(partNumberCollection, additionalProductDetials); 

Wie bekomme ich die zurückgegebenen Typen, damit ich sie verwenden kann? Ich habe versucht, nur partNumberCollection zu verwenden, aber es hat nur die await Eigenschaften zur Verfügung.

+1

Der Compiler sollten Sie ohne eine Warnung über die Verwendung von 'async' werden geben 'erwarten' in' ProcessAdditionalProductDetialsAsync'. Ist das dein tatsächlicher Code oder macht es wirklich eine "erwarten"? Woher kommt die eBay-API? –

+1

Ja, der Compiler warnt, dass diese Methode keine Wartezeit hat, aber die Wartezeit in der Elternmethode ist. –

+1

Sie sollten auf die Compiler-Warnung achten; es sollte ein 'erwarten' * in dieser Methode * geben, wenn es" asynchron "ist. Wenn Sie Code in einem Hintergrund-Thread ausführen möchten, verwenden Sie 'Task.Run'; wenn Sie E/A (d. h., die eBay-API), sollte es natürlich-asynchrone Methoden verwenden. –

Antwort

18

Verwenden Result Eigenschaft auf Task-Klasse:

await Task.WhenAll(partNumberCollection, additionalProductDetials); 

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

Sie sollten 'await' anstelle von' Result' verwenden, um das Umbrechen von Ausnahmen in einer 'AggregateException' zu vermeiden. –

12

Wenn die Aufgabe zurückgegeben von Task.WhenAll abgeschlossen hat, die alle Aufgaben bedeutet, dass Sie übergeben, um es zu abgeschlossen haben. Dies wiederum bedeutet, dass Sie die Eigenschaft Result jeder Aufgabe verwenden können, ohne dass die Gefahr einer Blockierung besteht.

string details = additionalProductDetials.Result; 

Alternativ können Sie die Aufgaben warten, für die Übereinstimmung mit anderen Asynchron-Code:

string details = await additionalProductDetials; 

Auch dies garantiert nicht zu blockieren - und wenn Sie später die Task.WhenAll aus irgendeinem Grund entfernen (zB Sie sind froh, die Details zu verwenden, um eine andere Aufgabe zu starten, bevor Sie die Teilenummersammlung erhalten haben. Dann müssen Sie den Code nicht ändern.

7

Ihre async Methode fehlt von await Operatoren und wird synchron ausgeführt. Während Sie nicht blockierende API aufrufen, können Sie Task.Run() verwenden, um cpu-gebundene Arbeit an Hintergrundthread zu tun.

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

und Ergebnis erhalten

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

Die übergeordnete Methode, die dies aufruft, ist mit async markiert und verwendet den await Task.WhenAll, führt dies nicht die obige Methode async aus? –

+0

ja tut es aber nur, wenn Sie 'Task.WhenAll()' verwenden. –

+0

Ja, ich bin, sehen Sie die letzte Codezeile in der Frage, danke –

-1

diesen Code Versuchen:

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

Verbrauch:

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

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