行为异步等待控制台应用程序与WPF

时间:2019-02-27 09:36:42

标签: c# wpf asynchronous async-await deadlock

我是异步等待的新手。我想我了解控制台应用程序的示例。将相同的代码传输到WPF时,会出现死锁,我也不知道为什么。

// All as expected
// Output:
// LongOperationAsync Start
// Before task.Wait();
// LongOperationAsync End
// After task.Wait();
// Result: 4711

class Program {
    public static void Main() {
        Task<int> task = LongOperationAsync();
        //Console.ReadKey();
        Console.WriteLine("Before task.Wait();");
        task.Wait();
        Console.WriteLine("After task.Wait();");
        var result = task.Result;
        Console.WriteLine("Result: {0}", result);
        Console.ReadKey();
    }

    static async Task<int> LongOperationAsync() {
        Console.WriteLine("LongOperationAsync Start");
        await Task.Delay(1000);
        Console.WriteLine("LongOperationAsync End");
        return 4711;
    }
}

这是阻塞的WPF代码:

// WPF handler Output:
// LongOperationAsync Start
// Before task.Wait(); => Blocking

private void button2_Click(object sender, EventArgs e) {
    Task<int> task = LongOperationAsync();
    Debug.WriteLine("Before task.Wait();");
    task.Wait();
    Debug.WriteLine("After task.Wait();");
    var result = task.Result;
    Debug.WriteLine("Result: {0}", result);
}

private async Task<int> LongOperationAsync() {
    Debug.WriteLine("LongOperationAsync Start");
    await Task.Delay(1000);
    Debug.WriteLine("LongOperationAsync End");
    return 4711;
}

2 个答案:

答案 0 :(得分:5)

在两种情况下,代码均会阻塞。这两个例子都是不好的。两者都不异步执行。

正确的 控制台代码为:

public static async Task Main()
{
    Console.WriteLine("Before LongOperationAsync");

    int result = await LongOperationAsync();

    Console.WriteLine("After LongOperationAsync");
    Console.WriteLine("Result: {0}", result);
    Console.ReadKey();
}

等效的WPF代码为:

private async void button2_Click(object sender, EventArgs e)
{
    Debug.WriteLine("Before LongOperationAsync");

    int result = await LongOperationAsync();

    Debug.WriteLine("After LongOperationAsync");
    Debug.WriteLine("Result: {0}", result);
}

async是语法糖,它允许使用await关键字。 await异步唤醒,以完成已经Task.Delay()之类的已经异步的操作,而不会阻塞原始线程。该异步操作完成后,await将在原始同步上下文中恢复执行。在WPF应用程序的情况下,这就是UI线程。这就是允许在await之后更新UI的原因。

async void仅适用于事件处理程序,例如button2_click。在所有其他情况下,应使用async Task。无法等待async void方法,应用程序也不知道它们是否完成。

答案 1 :(得分:-1)

在您的示例中,您可以将按钮单击修改为异步。您的任务受阻,因为您从不启动他,也无法在不启动任务的情况下传递“ wait()”调用。

在修改后的按钮单击方法下面。

private async void button2_Click(object sender, EventArgs e)
{
    var result = await LongOperationAsync();
    Debug.WriteLine("Result: {0}", result);
}