Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用异步等待仍然冻结GUI_C#_User Interface_Asynchronous_Async Await - Fatal编程技术网

C# 使用异步等待仍然冻结GUI

C# 使用异步等待仍然冻结GUI,c#,user-interface,asynchronous,async-await,C#,User Interface,Asynchronous,Async Await,我希望在单独的线程中处理长时间运行的操作,并使用异步/等待模式尽快将控制返回GUI线程,如下所示: private async void Button_Click(object sender, RoutedEventArgs e) { await Test(); txtResult.Text = "Done!"; } private Task Test() { Thread.Sleep(3000); return Task.FromResult(0); } 问

我希望在单独的线程中处理长时间运行的操作,并使用异步/等待模式尽快将控制返回GUI线程,如下所示:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    await Test();
    txtResult.Text = "Done!";
}

private Task Test()
{
    Thread.Sleep(3000);
    return Task.FromResult(0);
}
问题是,它会将GUI冻结3秒钟(在3秒钟后显示“完成”之前,它将变得无响应)。我做错了什么

编辑: 我试图替换以下逻辑:

private void Button_Click(object sender, RoutedEventArgs e)
{
    var thread = new Thread(() => Test(Callback));
    thread.Start();
}

private void Callback()
{
    Dispatcher.Invoke(() =>
        txtResult.Text = "Done!");
}

private void Test(Action callback)
{
    Thread.Sleep(3000); //long running operation, not necessarily pause
    callback();
}

在实际的项目中,我有不同于睡眠的长时间运行逻辑,它仍然冻结GUI,所以用任务代替它。延迟并不能解决任何问题。此外,我不明白你为什么还要使用另一个睡眠命令?异步/等待设计如何要求这一点?

您使用的是阻止线程的
线程。Sleep
。 改为使用
Task.Delay
,它在内部使用计时器并异步将控制权返回给调用方:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    await TestAsync();
    txtResult.Text = "Done!";
}

private async Task<int> TestAsync()
{
    await Task.Delay(3000);
    return 0;
}

您可以使用
Task.Run
Task.Factory.StartNew
在另一个线程上执行
Test()
或一些长时间运行和/或阻塞操作:

private async void Button_Click(object sender, RoutedEventArgs e)
{
    await Task.Run(() => Test());
    txtResult.Text = "Done!";
}

异步的可能重复不会导致代码在单独的线程上运行。它允许在创建要在另一个线程上运行的任务或执行要等待的IO绑定任务的代码上使用当前线程时不被阻止。不过,您的方法不做这两件事。感谢您的回复,在实际项目中,我有长时间运行的逻辑,而不是睡眠,请参阅编辑的问题。好的,所以等待任务。运行(测试)异步运行,而等待任务同步运行?wait Task()与直接调用Task()相比有什么意义?@EugeneKr
wait
只是一个用于向编译器标记简单提示的关键字。异步不是由
await
完成的,而是由正在等待的底层方法完成的。这意味着,例如,如果您正在使用
HttpClient
执行异步IO,它公开了自然异步方法,那么当您
wait
它的一个方法时,控件将返回到调用方法。当您使用
Task.Run
时,您是在线程池线程上显式运行委托,这与使用自然异步API不同,后者不需要额外的线程。我开始理解这一点。。。我想是吧。仍然没有看到它在哪里有用。尽管如果我面前有一段使用await Test()的示例代码会容易得多,如果可能的话,与我提供的代码类似。希望你还有点耐心:)我几乎看不出等待任务的例子。延迟是有用的。@EugeneKr我不太清楚你的意思<代码>等待测试(),按照您的示例,不异步执行任何操作。它有一个阻塞部分,使用
Thread.Sleep
模拟,并使用实用工具
Task。FromResult
同样不异步,它只使用
TaskCompletionSource
创建一个已完成的
Task
对象。等待它只会阻止调用线程。对不起,为什么它应该是等待任务。运行(()=>Test());而不仅仅是等待Test()?Test()返回一个同步任务,仅仅等待它不会在单独的线程上启动任务。对于这一点的解释比我的解释要好得多:“async和await关键字不会导致创建额外的线程。”以及“您可以使用Task.Run将CPU绑定的工作移动到后台线程”。Task.Run是任务并行库的一部分。在这种情况下,它很好地发挥了等待的作用。在c#中有很多方法可以在后台做一些事情。为了更好地理解,我建议阅读此快速演练
private async void Button_Click(object sender, RoutedEventArgs e)
{
    await Task.Run(() => Test());
    txtResult.Text = "Done!";
}