Laden...

Mit Task.Wait() auf einen Task warten, der nicht mit Task.Run() gestartet wurde

Erstellt von tkrasinger vor 10 Jahren Letzter Beitrag vor 10 Jahren 4.451 Views
Thema geschlossen
T
tkrasinger Themenstarter:in
574 Beiträge seit 2008
vor 10 Jahren
Mit Task.Wait() auf einen Task warten, der nicht mit Task.Run() gestartet wurde
private void Button_Click(object sender, RoutedEventArgs e)
{
    //Variante a) not working:
    Task t = CreateTestFile();
    t.Wait();

    //Variante b) working:
    Task t2 = Task.Run( () => CreateTestFile());
    t2.Wait();
}

private async Task CreateTestFile()
{
    IStorageFolder rootPath;
    if (!(await FolderExists(ApplicationData.Current.LocalFolder, "Test")))
    {
        rootPath = await ApplicationData.Current.LocalFolder.CreateFolderAsync("Test");
    }
    else
    {
        rootPath = await ApplicationData.Current.LocalFolder.GetFolderAsync("Test");
    }
    var file1 = await rootPath.CreateFileAsync(DateTime.Now.ToString("HHmm") + ".txt");
    return;
}

public async Task<bool> FolderExists(IStorageFolder rootPath, string foldername)
{
    try
    {
        await rootPath.GetFolderAsync(foldername);
        return true;
    }
    catch
    {
        return false;
    }
}

Wenn ich den Button klicke und den unteren Code aufrufe mit Task.Run() dann funktioniert das einwandfrei und relativ flott.
Wenn ich es allerdings mit Task.Wait() ausführe, dann passiert irgendwie gar nichts, der Code bleibt irgendwo hängen. Wenn ich dann probiere langsam durchzudebuggen, läuft auch der Code durch ...

Was mache ich falsch bzw. wo liegt der Unterschied?

16.806 Beiträge seit 2008
vor 10 Jahren

Am korrektesten wäre eigentlich



private async void Button_Click(object sender, RoutedEventArgs e)
{
   String testFile = await CreateTestFile();
}


private async Task<String> CreateTestFile()
 {
     IStorageFolder rootPath;
     if (!(await FolderExists(ApplicationData.Current.LocalFolder, "Test")))
     {
         rootPath = await ApplicationData.Current.LocalFolder.CreateFolderAsync("Test");
     }
     else
     {
         rootPath = await ApplicationData.Current.LocalFolder.GetFolderAsync("Test");
     }

     var testFile = DateTime.Now.ToString("HHmm") + ".txt";

     var file1 = await rootPath.CreateFileAsync(testFile);

     return testFile ;
 }

49.485 Beiträge seit 2005
vor 10 Jahren

Hallo tkrasinger,

eine Task wird nicht durch das reine Erstellen gestartet, sondern erst durch den Aufruf von Run*. Entsprechend macht Wait es auch nur Sinn, wenn die Task vorher mit Run gestartet wurde. Sonst wird endlos gewartet. Mit Task.Wait kann man natürlich nichts ausführen, sondern nur auf die Ausführung warten**.

Allerdings macht Run und Wait direkt hintereinander normalerweise keinen Sinn, weil der Code dann zwar in einem anderen Thread läuft, aber der aufrufende Thread solange blockiert ist, wie der Code läuft und damit (ziemlich) genauso lange, als wenn er den Code selbst ausgeführt hätte. Gerade wenn der aufrufende Thread wie in deinem Beispiel offensichtlich der GUI-Thread ist, ist das unsinnig, siehe [FAQ] Warum blockiert mein GUI?, Abschnitt "Noch eine Falle".

Wenn man - wie von Abt vorgeschlagen - await verwendet, teil der Compiler den Code der Methode so auf, dass der aufrufende Thread nicht blockiert wird.

* es gibt zwar noch andere Wege eine Task zu starten außer Run, aber die Erzeugung alleine reicht eben nicht

** Wait führt zwar nicht zwangsläufig zu einer Blockierung des aktuellen Threads, da der aktuelle Thread, sofern möglich, die Task, auf die per Wait "gewartet" wird, ausführen kann, aber das ändert nichts daran, dass der Thread nichts anderes tun kann, bis die Task fertig ist.

herbivore

Thema geschlossen