2016-03-20 4 views
2

Ich werde versuchen, meine Frage anhand des sinnlosen Beispiels zu illustrieren, das Sie unten sehen.Ist async-await eine notwendige Bedingung, um zwei unabhängige Aufgaben in meinem Programm parallel auszuführen?

using System; 
using System.IO; 
namespace PointlessProgram 
{ 
    class PointlessClass 
    { 
     public static void WriteFooToTextFile () 
     { 
      using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Users\Hillary\Documents\PointlessFolder\Foo.txt")) 
      { 
       file.Write("Foo"); 
      } 
     } 

     public static void WriteBarToTextFile () 
     { 
      using (System.IO.StreamWriter file = new System.IO.StreamWriter(@"C:\Users\Hillary\Documents\PointlessFolder\Bar.txt")) 
      { 
       file.Write("Bar"); 
      }  
     } 

     static void Main() 
     { 
      WriteFooToTextFile(); // (A) 
      WriteBarToTextFile(); // (B)  
     } 
    } 
} 

Hier (B) braucht nicht nach (A) ausgeführt werden, weil es nicht auf jedem Ausgang von (A) erzeugt abhängt, und neighter tut (A) auf (B) ab. Nehmen wir an, mein Computer hat 2 Prozessoren und wird all seine Verarbeitungsleistung dem Ausführen dieses Programms widmen. Wird der Compiler herausfinden, dass (A) und (B) parallel ausgeführt werden können, oder wird es nacheinander ausgeführt, es sei denn, ich schreibe explizit meinen Code, um die Maschine darauf hinzuweisen, dass (A) nicht beendet wird, bevor (B) ausgeführt wird? Und wenn ja ist, async-await, wie ich diese Ausführung ändern von

=== 
A 
--- 
B 
=== 

zu

======== 
A | B 
======== 

???

Was ich verwirrend finden über async-await ist, dass Sie nicht denken, in Bezug auf das Programm in unabhängige Aufgaben Partitionierung A, B, C, ...; Sie denken stattdessen an "diese Aufgabe" und "alles andere" und alles, was Sie tun, sagt "alles andere kann weiter laufen, während diese Aufgabe ausgeführt wird".

Bitte helfen Sie mir zu verstehen.

+2

Ich bin nicht sicher, was Sie nicht schon fragen können durch die Suche und das Lesen über async, Multithreading, TPL (Task Parallel Library) usw. –

+1

@KoryGill beantwortet werden Ich stimme zu..aber jemand, der für den Präsidenten kandidiert, hat nicht die Zeit dafür;). – i3arnon

Antwort

1

Wenn Ihr Programm angezeigt wird, wird zunächst "A" und dann "B" ausgeführt, nachdem "A" abgeschlossen wurde. Sie könnten das async/await Modell implementieren, da wir uns jedoch nicht wirklich mit den Rückgabewerten befassen, wäre ein sicherer und prägnanterer Fall einfach, jeden Methodenaufruf für einen neuen Thread zu starten. Wir können mit beginnen:

static void Main() 
{ 
    Task.Run(() => WriteFooToTextFile()); // (A) 
    Task.Run(() => WriteBarToTextFile()); // (B)  
} 

(. Für die Nutzung des Task Objekt, wir haben eine using System.Threading.Tasks; Richtlinie hinzufügen)

Ein weiteres Argument der Task-Modell zu verwenden, ist, dass das async/await Modell ist nicht Multithreading, sondern nur asynchrone Ausführung auf dem gleichen Anwendungsthread - also, um beide CPUs am besten zu nutzen, sollten Sie auf separaten Threads ausgeführt werden.

Natürlich müssen wir uns jetzt mit Multithreading einer potentiellen Race Condition bewusst sein. Da in Ihrem Beispiel keine Abhängigkeit zwischen den einzelnen Aufgaben besteht, sollte es keine vorhersehbaren Auswirkungen darauf geben, dass eine Aufgabe zuerst abgeschlossen wird. Wir möchten jedoch nicht, dass das Programm beendet wird, bis beide Threads abgeschlossen sind. Außerdem möchten wir nicht, dass Ausnahmen von einem Prozess sich gegenseitig stören, aber wir möchten im Idealfall alle Ausnahmen gleichzeitig behandeln. Daher könnten wir die Anrufe auf die folgende Weise implementieren:

static void Main() 
{ 
    try 
    { 
     Task.WaitAll(new Task[] { 
      Task.Run(() => WriteFooToTextFile()), // (A) 
      Task.Run(() => WriteBarToTextFile()) // (B) 
     }); 
    } 
    catch (AggregateException e) 
    { 
     // Handle exception, display failure message, etc. 
    } 
} 
5

Wird der Compiler herausfinden, dass (A) und (B) parallel ausgeführt werden können?

Nein. Der Compiler führt keine automatische Parallelisierung für Sie durch.

Und wenn ja, ist async-erwarten, wie ich diese Ausführung ändern?

Nicht so gut. async-await hat damit eigentlich nichts zu tun.

Ihr Code kann sequentiell sein, egal ob synchron oder nicht. Und es kann parallel sein, ob es asynchron ist oder nicht.

Zum Beispiel synchron und parallel:

var task1 = Task.Run(() => WriteFooToTextFile()); 
var task2 = Task.Run(() => WriteBarToTextFile()); 
Task.WaitAll(task1, task2); 

und asynchrone und sequentielle:

await WriteFooToTextFileAsync(); 
await WriteBarToTextFileAsync(); 

Durch Ihre Operationen wirklich machen asynchrone Sie Fäden befreien und es ihnen ermöglichen, Ihre auf andere Teile zu arbeiten Anwendung. Aber wenn es keine anderen Teile gibt, sitzen sie und warten in der ThreadPool und Sie gewinnen nicht viel.

2

Ihr Code ist synchron, also wird A ausgeführt, dann wird B ausgeführt. Um sie gleichzeitig auszuführen, sollten Sie den Befehl Task.Run() verwenden, um sie in einer separaten Task auszuführen, und dann await sie abzuschließen.So

:

public static async Task Write() 
{ 
    Task t1 = Task.Run(() => WriteFooToTextFile()); 
    Task t2 = Task.Run(() => WriteBarToTextFile()); 
    await Task.WhenAll(t1, t2); 
} 

mit der Nutzung von:

await PointlessClass.Write(); 

Notiere die Unterschrift des Schreibverfahren ist jetzt async Task. Sie müssen Ihren Event-Handler (oder was auch immer diesen Code auslöst), auch async.

Wie im Folgenden erwähnt, müssen Sie Ihren Code nicht asynchron machen, um die parallelen Operationen zu erreichen. Es ist in der Regel getan, um das Blockieren des UI-Threads in WPF- und WinForms-Anwendungen zu stoppen. Aus diesem Grund sehen Sie in vielen Beispielen, dass der Code Hand in Hand geht.

Wenn Sie Konsole verwenden, versuchen:

static void Main() 
{ 
    MainAsync().Wait(); 
} 

static async Task MainAsync() 
{ 
    Task t1 = Task.Run(() => WriteFooToTextFile()); 
    Task t2 = Task.Run(() => WriteBarToTextFile()); 
    await Task.WhenAll(t1, t2); 
} 

Siehe: Async Console App für weitere Informationen.

+1

'Main' kann nicht async sein – i3arnon

+0

Der Einstiegspunkt einer Konsolenanwendung kann' Task' nicht zurückgeben oder asynchron sein. –

+0

Yup natürlich. Ich nahm (vielleicht zu Unrecht) an, dass dies ein triviales Beispiel war, aber in eine eigenständige Klasse implementiert werden sollte. –

2

Die oben genannten werden nacheinander ausgeführt, imperative Sprachen erwarten vom Entwickler, dass er explizit die Regeln der Ausführung angibt. Die meisten Sprachen wurden ursprünglich für ein Einkernsystem entwickelt und folgen einer Von-Neumann-Architektur.

https://en.wikipedia.org/wiki/Von_Neumann_architecture

So als Folge, sind Sie erforderlich, ausdrücklich zu erwähnen, was sicher parallel ausgeführt werden können. Der Compiler sollte so behandelt werden, als wäre er dumm.

In Bezug auf Möglichkeiten, um eine parallele Aufgabe zu erreichen, könnten Sie wie Parallel.Invoke verwenden. Ich würde wahrscheinlich einfach auf Parallel invoke oder Task.Run in der obigen Instanz von Code zurückgreifen.

Verwandte Themen