2017-05-16 14 views
1

versuchen zu verstehen, warum die Aufgaben gestartet werden, wenn ToArray() ausgeführt wird. und warum der Breakpoint, den ich in die DoSomething-Methode einfüge, niemals getroffen wird.LINQ/async/erwarten

private async void MyMethod() 
{ 
     await NewMethod(); 
     string[] array = { "http://google.com", "http://microsoft.com"}; 
     IEnumerable<Task<string>> query = from url in array select DoSomething(url); 
     Task<string>[] tasks = query.ToArray(); 
     string[] contents = await Task.WhenAll(tasks); 
} 

private async Task<string> DoSomething(string url) 
{ 
     HttpClient hc = new HttpClient(); 
     string content = await hc.GetStringAsync(url); 
     return content; 
} 

wenn die ToArray() tatsächlich die Aufgaben beginnt, wird die Ausführung an den einzelnen Stützpunkten in der DoSomething Methode stoppen soll, richtig?

danke

+5

das ist das Verhalten von Linq. Die tatsächliche Abfrage wird nur ausgeführt, wenn Sie etwas mit der Ergebnismenge wünschen. Sehen Sie sich die verzögerte und direkte Abfrageausführung in linq an. –

+0

Geben Sie den DoSomething-Code an und zeigen Sie an, wo Sie den Breakpoint platzieren. Es gibt einige Aufgaben, die zurückgegeben werden, die Sie noch ausführen müssen, glaube ich. –

+0

Und zeigen Sie uns, wie Sie die '' task's ('warten',' WaitAll() ',' WhenAny() 'usw. ausführen. – dymanoid

Antwort

0

Überprüfen Sie die folgenden Versionen des Codes aus Async Main in einer Konsole-Anwendung:

private async Task MyMethod() 
{ 
    await NewMethod(); // Contains Place holder wait code 
    string[] array = { "http://google.com", "http://microsoft.com" }; 
    IEnumerable<Task<string>> queryTasks = from url in array select DoSomething(url); 
    string[] contents = await Task.WhenAll(queryTasks); 
    contents.Dump(); 
} 

private async Task<string> DoSomething(string url) 
{ 
    HttpClient hc = new HttpClient(); 
    string content = await hc.GetStringAsync(url); 
    return content; 
} 

private async Task NewMethod() 
{ 
    // Placeholder Task.Delay 
    await Task.Delay(1000); 
} 

Jetzt MyMethod() kann in folgenden zwei Arten aufgerufen werden:

Erstens:

async Task Main() 
    { 
     await MyMethod(); 
    } 

Zweitens:

async void Main() 
    { 
     await MyMethod(); 
    } 

Obwohl es ideal möglich sein soll, in den Fällen, sowohl oben zu debuggen, aber im Falle von void Main() wird Haupt-Thread zurückkehren/Ausfahrt vor Code beim Haltepunkt in der DoSomething, ein einfaches Beispiel wäre, derzeit NewMethod() enthält await Task.Delay(1000);, ändern Sie es in await Task.Delay(1); und Sie werden sehen, meist wird es in jedem Fall brechen, sonst die void Main wird beendet, bevor der Breakpoint in der DoSomething Methode bricht den Code-Fluss. Stattdessen wird Task Main() in jedem Fall Code-Breaking sicherstellen, da er nun auf die Beendigung der Task warten muss, bevor er fortfährt.

Weitere wichtige Details:

  1. Sie nicht query.ToArray() brauchen die Ausführung zu beginnen, wo Task.WhenAll macht den Job als die IEnumerable<Task<string>> geliefert, aber immer noch eine verzögerte Ausführung, die ToArray() Anruf früher materialisiert wurde mit