2017-02-07 8 views
-1

Ich bin von diesem Code verwirrt. Gemäß der Dokumentation, die diesen Code enthält, ruft sie jede Aufgabe auf, die ihnen ermöglicht, gleichzeitig auszuführen, und erwartet dann, dass beide vollständig sind.So führen Sie mehrere asynchrone Tasks gleichzeitig aus

Ich verstehe nicht, wie die Reihenfolge der Ausführung funktioniert. Wenn die Task var firstTask = DoSomethingAsync(); deklariert wird, führt dies dazu, dass die Task ausgeführt wird? Ich dachte, es ist synchron ohne einen Erwartungsausdruck.

public async Task RunConcurrentTasks() 
{ 
    var firstTask = DoSomethingAsync(); 
    var secondTask = DoSomethingElseAsync(); 

    await firstTask; 
    await secondTask; 
} 

Erzielt auch dieser Code das gleiche Ergebnis?

public async Task RunConcurrentTasks() 
{ 
    var firstTask = DoSomethingAsync(); 
    var secondTask = DoSomethingElseAsync(); 

    await Task.WhenAll(firstTask, secondTask); 
} 
+0

@Igor sodass dieser Code neu geschrieben werden kann: 'var firstTask = DoSomethingAsync(); var secondTask = DoSomethingElseAsync(); 'bewirkt, dass jede Aufgabe aufgerufen wird und die Ausführung beginnt? Wie würde ich es synchron machen, wenn ich wollte? –

+0

Wenn Sie eine neue Frage haben, wie Sie die asynchrone Methode synchron ausführen können, stellen Sie sie bitte als Frage (offensichtlich gelten alle Standardanforderungen). Es ist nicht möglich, einen Kommentar wegen mangelnder Forschung abzulehnen ... –

Antwort

0

auf die Async Methode aufrufen, mit den parenthesys () wie DoSomethingAsync(); wird die Ausführung der Async-Funktionalität beginnen. Es wird sofort eine Task zurückgegeben, die Informationen über die Async-Funktionalität enthält, die gerade ausgeführt wird, und das System darüber informiert, wenn es fertig ist.

Um sie in der Reihenfolge auszuführen, warten Sie nur auf jeden einzeln, anstatt den WhenAll Aufruf zu erwarten. Als solche:

public async Task RunConcurrentTasks() 
{ 
    await DoSomethingAsync(); 
    await DoSomethingElseAsync(); 
} 

jetzt DoSomethingElseAsync wird vor der Ausführung auf dem Anruf DoSomethingAsync warten.

+0

Warum haben Sie solch eine gefährliche Empfehlung ausgesprochen, '.Result' in einer Antwort zu verwenden, wenn es in der Frage nicht einmal gefragt wurde? –

+0

Nun, er hat gefragt, wie man die Aufgabe synchron ausführt. In seinem Kommentar. – maksymiuk

+0

OP sollte getrennte Frage gestellt haben (eigentlich hätte man selbst nach Antworten suchen sollen - es gibt viele Diskussionen zum Thema SO). Es gibt wirklich keinen guten Grund, ".Result" nur ohne die richtigen Links zu Problemen zu erwähnen, die dieser Aufruf verursacht. Wäre im Kommentar viel besser beantwortet (; oder erst im Kommentar in Frage, aber das würde schon breite Frage viel zu weit bringen) –

1

Durch Deklarieren der Task var firstTask = DoSomethingAsync(); Führt dies dazu, dass die Aufgabe ausgeführt wird?

Ja.

Wie wird dann die Ausführung zur nächsten Zeile weitergeleitet, um die zweite Aufgabe aufzurufen?

Es wird DoSomethingAsync laufen, bis es seine erste await trifft, die ergibt. An diesem Punkt gibt DoSomethingAsync eine Aufgabe zurück, die noch nicht abgeschlossen ist, und der Aufrufer RunConcurrentTasks fährt mit der nächsten Zeile fort.

Ich dachte, es ist synchron ohne einen Ausdruck zu erwarten.

Nein, es ist immer noch asynchron. await nicht run alles. await führt dazu, dass der konsumierende Code asynchron auf die Aufgabe wartet ("await") wartet.

Sie können meine async intro hilfreich finden.

6

var firstTask = DoSomethingAsync(); verursacht dies die Ausführung der Aufgabe?

Ja. Es war besser! DoSomethingAsync verspricht in seinem Namen zu etwas asynchron zu tun, also wenn es Sie nicht eine ausführende Aufgabe zurückgibt, dann ist sein Name eine Lüge.

Wie wird dann die Ausführung zur nächsten Zeile weitergeleitet, um die zweite Aufgabe aufzurufen?

Ich verstehe die Frage nicht.

Ich dachte, es ist synchron ohne einen Ausdruck zu erwarten.

Ihr Glaube ist falsch. "Warten" bedeutet nicht "mache das asynchron". Erwartet weder Asynchronität, noch zerstört er sie; Es verwaltet lediglich vorhandene Asynchronität. DoSomethingAsync ist bereits asynchron unabhängig von await. Erneut, sagt es, dass es etwas asynchron tut, so dass besser sein sollte, was es tut!

await in Ihrem Beispiel ist nur return. Es bedeutet "zu meinem Aufrufer zurückkehren und diese Methode irgendwann nach der erwarteten Aufgabe in der Zukunft erneut ausführen." Es ist ein asynchrones Warten.

Denken Sie an await als wie yield return. Wenn Sie sich in einem Iteratorblock befinden und eine Renditerückgabe auftritt, wird die Methode zurückgegeben, und dann wird sie an der Stelle fortgesetzt, an der sie irgendwann in der Zukunft aufgehört hat. await ist im Grunde das Gleiche; nur die Mechanismen sind etwas anders.

Eine andere Möglichkeit, daran zu denken ist, dass await einen Punkt markiert, wo die aktuelle Methode nicht ausgeführt werden kann, bis die erwartete Aufgabe abgeschlossen ist. Da die Methode nicht weiter ausgeführt werden kann, wird sie zurückgegeben.

Noch einmal, await tut nichts zu einem Anruf auf der rechten Seite. Es ist nur ein Operator, und es gehorcht alle normalen Regeln der Operatoren:

await Foo(); 

und

var blah = Foo(); 
await blah; 

sind die gleiche Sache, genau wie

var x = Foo() + Bar(); 

und

var f = Foo(); 
var b = Bar(); 
var x = f + b; 

sind das Gleiche. Erwarte nichts Magisches zu seinen Operanden mehr als + macht etwas Magisches zu seinen Operanden. Es ist nur eine besondere Art der Rückkehr.

Auch macht dieser Code das gleiche?

Bitte stellen Sie nicht zwei Fragen in einer Frage. Stellen Sie zwei Fragen, wenn Sie zwei Fragen haben.

Die Frage ist unklar. Die Semantik beider Workflows besteht darin, dass die von RunConcurrentTasks zurückgegebene Aufgabe als abgeschlossen gemeldet wird, wenn beide untergeordneten Aufgaben abgeschlossen sind, falls Sie dies fragen.

+1

Deine Aussage "Denke an sehnst du dich wie Rendite" wirklich geklärt async/warte auf mich. – OldFart

+0

@OldFart: Sie können sich denken 'IEnumerable ', 'IObservable ', 'Func ' und 'Aufgabe ' als alle die gleiche Sache mit kleinen Variationen. Eine Sequenz ist "gebe den nächsten Wert, wenn ich frage". Ein Observable ist "den nächsten Wert bereitstellen, wenn es verfügbar ist". Eine Funktion ist "gebe einen einzelnen Wert, wenn ich frage". Eine Aufgabe ist "einen einzelnen Wert bereitstellen, wenn es verfügbar ist".Gleiche Sache; alles, was sich unterscheidet, ist (1) wie viele Werte zur Verfügung gestellt werden und (2) ob Sie * den Wert * ziehen * oder * gedrückt * haben. –

+0

@Eric Vielen Dank für diesen Kommentar über 'IEnumerable ', 'IObservable ', 'Func ' und 'Task '. Ihre Erklärung hilft, die Beziehung zwischen den Typen zu vereinheitlichen. –

0

Task Documentation

Die Task-Klasse stellt eine einzelne Operation, die keinen Wert zurückgibt und dass führt in der Regel asynchron. Aufgabenobjekte sind eine der zentralen Komponenten des aufgabenbasierten asynchronen Musters, das erstmals in .NET Framework 4 eingeführt wurde. Da die von einem Task-Objekt ausgeführte Arbeit in der Regel asynchron für einen Threadpool-Thread und nicht synchron für den Hauptanwendungsthread ausgeführt wird. .

Hier ist Ihr Code kommentiert, hoffentlich macht dies mehr Sinn.

public async Task RunConcurrentTasks() 
{ 
    // starts DoSomethingAsync and returns a Task which contains the information about the running state of that operation 
    // the thread that called this gets that Task as a result immediatly and can continue on to the next statement while this is running 
    var firstTask = DoSomethingAsync(); 

    // starts DoSomethingElseAsync and returns a Task which contains the information about the running state of that operation 
    // the thread that called this gets that Task as a result immediatly and can continue on to the next statement while this is running 
    var secondTask = DoSomethingElseAsync(); 

    // suspend the execution of the method until the awaited task completes 
    // only then do we proceed to the next line (assuming no exception was thrown) 
    await firstTask; 

    // suspend the execution of the method until the awaited task completes 
    // only then do we proceed to the next line (assuming no exception was thrown) 
    await secondTask; 
} 


public async Task RunConcurrentTasks() 
{ 
    // starts DoSomethingAsync and returns a Task which contains the information about the running state of that operation 
    // the thread that called this gets that Task as a result immediatly and can continue on to the next statement while this is running 
    var firstTask = DoSomethingAsync(); 

    // starts DoSomethingElseAsync and returns a Task which contains the information about the running state of that operation 
    // the thread that called this gets that Task as a result immediatly and can continue on to the next statement while this is running 
    var secondTask = DoSomethingElseAsync(); 

    // suspend the execution of the method until the awaited DoSomethingAsync AND DoSomethingElseAsync have completed 
    // only then do we proceed to the next line (assuming no Exceptions was thrown) 
    await Task.WhenAll(firstTask, secondTask); 
} 

Von Kommentaren

Wie würde ich es synchron zu tun, wenn ich will?

Await documentation

Die Await Bediener zu einer Aufgabe in einem asynchronen Verfahren angewandt wird, um die Durchführung des Verfahrens zu unterbrechen, bis die erwartete Aufgabe

Verwenden vervollständigt await unmittelbar nach jedem Anruf, Dadurch wird sichergestellt, dass die Ausführung nicht mit der nächsten Zeile fortgesetzt wird, bis ein Ergebnis (oder eine Ausnahme) von der Ausführung der erwarteten Aufgabe zurückgegeben wird. Es macht es eigentlich nicht synchron im technischen Sinn des Wortes. Nehmen Sie Ihr erstes Beispiel und ordnen Sie die Leitungen neu, so dass Sie nach dem Start der ersten Operation und vor dem Start der zweiten Operation await anrufen.

var firstTask = DoSomethingAsync(); 
await firstTask; 
var secondTask = DoSomethingElseAsync(); 
await secondTask; 

die auch als

await DoSomethingAsync(); 
await DoSomethingElseAsync(); 
+0

Wir machen ** NICHT ** "Ausführung auf diesem Thread stoppen". Der ganze * Punkt * von 'erwarten' ist zu vermeiden ** Ausführung auf dem Thread zu stoppen! –

+0

@EricLippert - schlechte Formulierung meinerseits, habe ich umformuliert (auch die Phrasierung in den Code-Kommentaren). – Igor

Verwandte Themen