2017-11-20 3 views
2

Angenommen, ich besitze eine Bibliothek für nicht auf UI basierende Anwendungen (ASP.NET) und auf UI-basierte Anwendungen (WinForm und WPF). Leider kann ich nicht vermeiden, IO-gebundene Arbeit und CPU-gebundene Arbeit zu mischen, aber ich lasse die Verbraucher DummyWorkAsync über Task.Run aufrufen oder nicht basierend auf ihren Anwendungstypen (Nicht-UI- oder UI-basierte Anwendungen).Gibt es einen Unterschied zwischen normalem Lambda und asynchronem Lambda?

class DummyService 
{ 
    public static async Task<int> DummyWorkAsync() 
    { 
    // Do some I/O first. 
    await Task.Delay(1000); 

    // Tons of work to do in here! 
    for (int i = 0; i != 10000000; ++i) 
     ; 

    // Possibly some more I/O here. 
    await Task.Delay(1000); 

    // More work. 
    for (int i = 0; i != 10000000; ++i) 
     ; 

    return 0; 
    } 
} 

Dies ermöglicht UI-basierte Verbraucher richtig Task.Run zu verwenden, um den Dienst zu nennen, während ASP.NET-Clients nur die Methode direkt wie folgt nennen würde.

private async void MyButton_Click(object sender, EventArgs e) 
{ 
    await Task.Run(() => DummyService.DummyWorkAsync()); 
} 

public class Home: Controller 
{ 
    public async Task<ActionResult> IndexAsync() 
    { 
    var result = await DummyService.DummyWorkAsync(); 
    return View(result); 
    } 
} 

Frage

ich in den UI-basierten Anwendungen interessiert. Gibt es einen Unterschied, ob ich

private async void MyButton_Click(object sender, EventArgs e) 
{ 
    await Task.Run(async() => await DummyService.DummyWorkAsync()); 
} 

statt

private async void MyButton_Click(object sender, EventArgs e) 
{ 
    await Task.Run(() => DummyService.DummyWorkAsync()); 
} 

verwenden?

+0

Der erste wäre nur nützlich, wenn Sie etwas nach dem Beenden von 'DummyWorkAsync' im UI-Thread tun müssen. Technisch gesehen wartet es eigentlich darauf, dass es fertig ist, aber den UI-Thread zwischenzeitlich nicht blockiert. – juharr

+0

@Clemens: Weil es im "hybriden" 'DummyWorkAsync' einige CPU-gebundene Werke gibt. Wir müssen 'Task.Run' in UI-basierten Apps für eine solche hybride asynchrone Methode verwenden. –

+1

Da Ihr IO zuerst geht (ich meine, warten Sie zuerst auf Task.Delay), warum fügen Sie nicht einfach ConfigureAwait (false) hinzu? Dann können Sie es auch von der Benutzeroberfläche aufrufen, ohne in Task.Run zu verpacken. – Evk

Antwort

3

Nein, es gibt keinen (signifikanten) Unterschied. Sie fragen im Grunde, was ist der Unterschied zwischen

static Task<int> Something() { 
    return SomethingAsync(); 
} 

und

static async Task<int> Something() { 
    return await SomethingAsync(); 
} 

Außer in Ihrem Fall es ist mehr Verpackungsaufgabe (Task.Run), so Unterschiede in Ausnahmen Ausbreitung beispielsweise, die Sie in einem anderen finden Fragen zum selben Thema sind in diesem Fall nicht relevant.

Denn das von - verwenden nur

await Task.Run(() => DummyService.DummyWorkAsync()); 

Das heißt, Gründe dafür, die nicht so klar sind. Da Ihr IO zuerst ausgeführt wird, können Sie ConfigureAwait(false) verwenden, um zu verhindern, dass die Steuerung an den aktuellen Synchronisationskontext zurückgegeben wird (was für Bibliotheken ohnehin eine gute Vorgehensweise ist). In diesem Fall nach dem ersten, den Rest (schwere CPU Arbeit) wartet auf Thread-Pool-Thread ausgeführt wird (mit Standard-Scheduler zumindest), so dass Sie nicht Task.Run in erster Linie verwendet werden müssen:

public static async Task<int> DummyWorkAsync() 
{ 
    // Do some I/O first. 
    await Task.Delay(1000).ConfigureAwait(false); 

    // Tons of work to do in here! 
    // no problem, we are not on UI thread anyway 
    for (int i = 0; i != 10000000; ++i) 
     ; 

    // Possibly some more I/O here. 
    await Task.Delay(1000).ConfigureAwait(false); 

    // More work. 
    for (int i = 0; i != 10000000; ++i) 
     ; 

    return 0; 
} 
Verwandte Themen