it-swarm.com.de

Führen Sie zwei asynchrone Tasks gleichzeitig aus und erfassen Sie die Ergebnisse in .NET 4.5

Ich habe eine Weile versucht, etwas zu bekommen, von dem ich dachte, dass es einfach wäre, mit .NET 4.5 zu arbeiten

Ich möchte zwei lange laufende Aufgaben gleichzeitig abfeuern und die sammeln
ergibt den besten C # 4.5 (RTM) Weg

Folgendes funktioniert, aber ich mag es nicht, weil:

  • Ich möchte, dass Sleep eine asynchrone Methode ist, damit es await andere Methoden kann
  • Es sieht einfach ungeschickt aus mit Task.Run()
  • Ich glaube nicht, dass dies überhaupt irgendwelche neuen Sprachfunktionen nutzt!

Arbeitscode:

public static void Go()
{
    Console.WriteLine("Starting");

    var task1 = Task.Run(() => Sleep(5000));    
    var task2 = Task.Run(() => Sleep(3000));

    int totalSlept = task1.Result + task2.Result;

    Console.WriteLine("Slept for a total of " + totalSlept + " ms");
}

private static int Sleep(int ms)
{
    Console.WriteLine("Sleeping for " + ms);
    Thread.Sleep(ms);
    Console.WriteLine("Sleeping for " + ms + " FINISHED");
    return ms;
}

Nicht funktionierender Code:

Update: Dies funktioniert tatsächlich und ist der richtige Weg, das einzige Problem ist der Thread.Sleep

Dieser Code funktioniert nicht, da der Aufruf von Sleep(5000) die Task sofort startet, sodass Sleep(1000) erst ausgeführt wird, wenn der Vorgang abgeschlossen ist. Dies ist wahr, obwohl Sleepasync ist und ich await nicht verwende oder .Result Zu früh aufrufe.

Ich dachte, vielleicht gibt es eine Möglichkeit, einen nicht laufenden Task<T> Zu erhalten, indem ich eine async -Methode aufrufe, damit ich dann Start() für die beiden Tasks aufrufen kann, aber ich kann ' t Finden Sie heraus, wie Sie durch Aufrufen einer asynchronen Methode einen Task<T> - Wert erhalten.

public static void Go()
{
    Console.WriteLine("Starting");

    var task1 = Sleep(5000);    // blocks
    var task2 = Sleep(1000);

    int totalSlept = task1.Result + task2.Result;

    Console.WriteLine("Slept for " + totalSlept + " ms");
}

private static async Task<int> Sleep(int ms)
{
    Console.WriteLine("Sleeping for " + ms);
    Thread.Sleep(ms);
    return ms;
}
106
Simon_Weaver

Sie sollten Task.Delay anstelle von Sleep für die asynchrone Programmierung verwenden und anschließend Task.WhenAll verwenden, um die Taskergebnisse zu kombinieren. Die Aufgaben würden parallel laufen.

public class Program
    {
        static void Main(string[] args)
        {
            Go();
        }
        public static void Go()
        {
            GoAsync();
            Console.ReadLine();
        }
        public static async void GoAsync()
        {

            Console.WriteLine("Starting");

            var task1 = Sleep(5000);
            var task2 = Sleep(3000);

            int[] result = await Task.WhenAll(task1, task2);

            Console.WriteLine("Slept for a total of " + result.Sum() + " ms");

        }

        private async static Task<int> Sleep(int ms)
        {
            Console.WriteLine("Sleeping for {0} at {1}", ms, Environment.TickCount);
            await Task.Delay(ms);
            Console.WriteLine("Sleeping for {0} finished at {1}", ms, Environment.TickCount);
            return ms;
        }
    }
73
softveda
async Task<int> LongTask1() { 
  ...
  return 0; 
}

async Task<int> LongTask2() { 
  ...
  return 1; 
}

...
{
   Task<int> t1 = LongTask1();
   Task<int> t2 = LongTask2();
   await Task.WhenAll(t1,t2);
   //now we have t1.Result and t2.Result
}
106
Bart

Während Ihre Sleep -Methode asynchron ist, Thread.Sleep ist nicht. Die ganze Idee von Async besteht darin, einen einzelnen Thread wiederzuverwenden und nicht mehrere Threads zu starten. Da Sie die Verwendung eines synchronen Aufrufs von Thread.Sleep blockiert haben, funktioniert dies nicht.

Ich gehe davon aus, dass Thread.Sleep ist eine Vereinfachung dessen, was Sie tatsächlich tun möchten. Kann Ihre tatsächliche Implementierung als asynchrone Methoden codiert werden?

Wenn Sie mehrere synchron blockierende Anrufe ausführen müssen, schauen Sie woanders hin, denke ich!

3
Richard

Um diesen Punkt zu beantworten:

Ich möchte, dass Sleep eine asynchrone Methode ist, damit es auf andere Methoden warten kann

sie können die Funktion Sleep möglicherweise folgendermaßen umschreiben:

private static async Task<int> Sleep(int ms)
{
    Console.WriteLine("Sleeping for " + ms);
    var task = Task.Run(() => Thread.Sleep(ms));
    await task;
    Console.WriteLine("Sleeping for " + ms + "END");
    return ms;
}

static void Main(string[] args)
{
    Console.WriteLine("Starting");

    var task1 = Sleep(2000);
    var task2 = Sleep(1000);

    int totalSlept = task1.Result +task2.Result;

    Console.WriteLine("Slept for " + totalSlept + " ms");
    Console.ReadKey();
}

wenn Sie diesen Code ausführen, wird Folgendes ausgegeben:

Starting
Sleeping for 2000
Sleeping for 1000
*(one second later)*
Sleeping for 1000END
*(one second later)*
Sleeping for 2000END
Slept for 3000 ms
2
asidis

Es ist Wochenende jetzt!

    public async void Go()
    {
        Console.WriteLine("Start fosterage...");

        var t1 = Sleep(5000, "Kevin");
        var t2 = Sleep(3000, "Jerry");
        var result = await Task.WhenAll(t1, t2);

        Console.WriteLine($"My precious spare time last for only {result.Max()}ms");
        Console.WriteLine("Press any key and take same beer...");
        Console.ReadKey();
    }

    private static async Task<int> Sleep(int ms, string name)
    {
            Console.WriteLine($"{name} going to sleep for {ms}ms :)");
            await Task.Delay(ms);
            Console.WriteLine("${name} waked up after {ms}ms :(";
            return ms;
    }
2
Arvis

Leider hilft Ihnen Task.WhenAll () nicht, wenn Ihre Methoden weitere erwarten. Asynchrone Methoden sind nicht parallel.

Für eine echte parallele Ausführung sollten Sie neue Aufgaben manuell starten, z. using Task.Run () oder ConfigureAwait (false).

Details finden Sie hier: https://www.wintellect.com/tasks-are-still-not-threads-and-async-is-not-parallel/

0
bside

Dieser Artikel hat viele Dinge erklärt. Es ist im FAQ Stil.

Async/Await FAQ

Dieser Teil erklärt, warum Thread.Sleep läuft auf demselben Original-Thread - was zu meiner anfänglichen Verwirrung führt.

Führt das Schlüsselwort "async" dazu, dass eine Methode in den ThreadPool eingereiht wird? Einen neuen Thread erstellen? Ein Raketenschiff zum Mars starten?

Und nein. Siehe die vorherigen Fragen. Das Schlüsselwort "async" gibt dem Compiler an, dass "await" innerhalb der Methode verwendet werden kann, sodass die Methode an einem Wartezeitpunkt angehalten und ihre Ausführung asynchron fortgesetzt werden kann, wenn die erwartete Instanz abgeschlossen ist. Aus diesem Grund gibt der Compiler eine Warnung aus, wenn in einer als "asynchron" gekennzeichneten Methode keine "Wartezeiten" vorhanden sind.

0
Simon_Weaver