我想这类事情一般不应该做,但我想了解为什么这段代码会阻止UI,而不是从await taskMain:

using System.Diagnostics;

namespace TasksTest
{
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
        }

        private void buttonTest1_Click(object sender, EventArgs e)
        {
            try
            {
                DoTest1Async().Wait();
            }
            catch (Exception exc) 
            {
                MessageBox.Show(exc.ToString());
            }
        }

        private static async Task DoTest1Async()
        {
            Task taskMain = Task.Run(() => {
                Debug.WriteLine("Test #1 completed");
            });
            await taskMain;
        }
    }
}

如果我没有使用Wait(),而是使用了aWait,它可以完美地工作.我想知道是否有一种方法可以同步执行DoTest1Async而不会阻止UI.

-编辑

在理解了调用等待方法会阻塞UI线程并且不允许已完成的任务taskMain返回到UI线程上下文并继续执行之后...为什么下一个代码替代方案不以同样的方式阻止用户界面线程?我仍然不明白,如果我在另一个线程中启动代码,而UI线程在线程中被阻塞,为什么taskMain可以返回.Join,但它不能在简单的Wait()指令中返回.这听起来很奇怪.也许Wait方法的实现需要修改...?

        private void buttonTest1_Click(object sender, EventArgs e)
        {
            Thread thread = new(() =>
            {
                try
                {
                    DoTest1Async().Wait();
                    Debug.WriteLine("Unblocked!!");
                }
                catch (Exception exc)
                {
                    MessageBox.Show(exc.ToString());
                }
            });
            thread.Start();
            thread.Join();
            Debug.WriteLine("Thread Finished!");
        }

推荐答案

但我想知道为什么这段代码会阻止用户界面

因为Task.Wait是一个阻塞操作:

Wait是一种同步方法,它使调用线程等待,直到当前任务完成.如果当前任务尚未开始执行,则Wait方法会try 从调度程序中移除该任务,并在当前线程上内联执行该任务.如果它无法这样做,或者如果当前任务已经开始执行,它会阻止调用线程,直到任务完成

未从等待任务Main返回

它返回,但随后的Wait调用会阻塞该线程.

如果我没有使用Wait(),而是使用了aWait,它可以完美地工作.

如果它有效--使用它,引入async-await的原因之一就是在与此完全相同的情况下使用.

我想知道是否有一种方法可以同步执行DoTest1Async而不会阻止UI.

不是的.顾名思义.

另外,请阅读史蒂芬·克利里的Don't Block on Async Code篇文章.阻塞不仅会冻结UI线程,还可能导致死锁(看起来您正在经历一个死锁).

.net相关问答推荐

无法在Designer、VS2022、. NET 8中打开WinForms表单'

在计算Total毫秒时,.NET TimeSpan类中是否存在错误?

Ubuntu 22.04 + JetBrains Rider 不能做脚手架 dbContext

双精度的 C++ 和 C# 十六进制值之间的差异

单线程单元 - 无法实例化 ActiveX 控件

调整小数精度,.net

.NET - WindowStyle = hidden 与 CreateNoWindow = true?

将毫秒转换为人类可读的时间间隔

string.Format 如何处理空值?

ILMerge 最佳实践

在 WPF 窗口中获取当前聚焦的元素/控件

extern 在 C# 中是如何工作的?

如何在 .NET 中将字符串转换为字节数组?

Linq查询分组并 Select 第一个项目

使用 .NET 中的代码更改桌面墙纸

参数命名:文件名还是文件名?

关闭 Visual Studio 中所有选项卡但当前选项卡的键盘快捷键?

DLL 中有什么以及它是如何工作的?

.NET 图形库?

Linq Query 不断抛出无法创建 System.Object 类型的常量值......,为什么?