C# 异步等待:主线程是否挂起?

C# 异步等待:主线程是否挂起?,c#,async-await,thread-state,C#,Async Await,Thread State,我在读关于async/await关键字的文章,我读到: 当逻辑流到达等待令牌时,调用线程 挂起,直到调用完成 我创建了一个简单的windows窗体应用程序,放置了两个标签、一个按钮和一个文本框,并编写了代码: private async void button1_Click(object sender, EventArgs e) { label1.Text = Thread.CurrentThread.ThreadState.ToStrin

我在读关于
async/await
关键字的文章,我读到:

当逻辑流到达等待令牌时,调用线程 挂起,直到调用完成

我创建了一个简单的
windows窗体应用程序
,放置了两个标签、一个按钮和一个文本框,并编写了代码:

        private async void button1_Click(object sender, EventArgs e)
        {
            label1.Text = Thread.CurrentThread.ThreadState.ToString();
            button1.Text =  await DoWork();
            label2.Text = Thread.CurrentThread.ThreadState.ToString();
        }

        private Task<string> DoWork()
        {
            return Task.Run(() => {
                Thread.Sleep(10000);
                return "done with work";
            });            
        }
private async void按钮1\u单击(对象发送方,事件参数e)
{
label1.Text=Thread.CurrentThread.ThreadState.ToString();
button1.Text=wait DoWork();
label2.Text=Thread.CurrentThread.ThreadState.ToString();
}
私有任务DoWork()
{
返回任务。运行(()=>{
睡眠(10000);
返回“已完成工作”;
});            
}
我不明白的是,当我点击按钮时,label1将运行文本
,标签将在10秒钟后才有相同的文本,但在这10秒钟内,我能够在文本框中输入文本,因此似乎主线程正在运行

那么,async/await是如何工作的呢

以下是本书的“截图”:


关于

异步
/
等待
创建一个状态机,为您处理延续。一种非常粗略的等效方法(没有一系列特征)是一种显式延拓方法,例如:

private void button1_Click_Continuation(string value)
{
    button1.Text = value;
    label2.Text = Thread.CurrentThread.ThreadState.ToString();
}

private void button1_Click(object sender, EventArgs e)
{
    label1.Text = Thread.CurrentThread.ThreadState.ToString();
    DoWork(button1_Click_Continuation);
}

private void DoWork(Action<string> continuation)
{
    Task.Run(() => {
        Thread.Sleep(10000);
        continuation("done with work");
    });
}
private void按钮1\u单击\u继续(字符串值)
{
按钮1.文本=值;
label2.Text=Thread.CurrentThread.ThreadState.ToString();
}
私有无效按钮1\u单击(对象发送者,事件参数e)
{
label1.Text=Thread.CurrentThread.ThreadState.ToString();
DoWork(按钮1\u单击\u继续);
}
私人无效工作(行动继续)
{
Task.Run(()=>{
睡眠(10000);
继续(“完成工作”);
});
}
请注意,我仍在使用
Task.Run
在单独的线程上运行。请注意,此版本无法跟踪进度(而原始版本可以将
按钮1的返回值更改为
任务
,以查看其是否已完成)


除了上述转换之外,系统还可以智能地判断是否在UI线程上启动了
任务
,并再次封送回UI线程,以确保一切按预期工作。这可能是您没有意识到的主要事情,但在状态机方面的扩展有时解释了
asyc
/
await
的真正含义(而不是将其视为神秘的)。

通过编写
await
,您的意思是-此时请停止执行该方法,等待
DoWork
完成,然后继续

在“异步方法中发生的事情”一节中,有一个关于
Async
方法中发生的事情的逐步解释,并附有图片

一个更好的解释是。查看下面的
waitsynchronouslyasync
waitsynchronouslyasync
的注释

该条还指出(我的重点):

等待运算符应用于异步方法中的任务,以暂停方法的执行,直到等待的任务完成。这项任务是正在进行的工作

private async void按钮1\u单击(对象发送方,事件参数e)
{
//调用异步运行的方法。
字符串结果=等待WaitAsynchronouslyAsync();
//调用同步运行的方法。
//string result=wait WaitSynchronously();
//显示结果。
textBox1.Text+=结果;
}
//以下方法异步运行。UI线程不可用
//在延迟期间被阻塞。您可以移动或调整Form1窗口的大小
//正在运行任务。延迟。
公共异步任务WaitAsynchronouslyAsync()
{
等待任务。延迟(10000);
返回“完成”;
}
//以下方法同步运行,尽管使用了async。
//线程处于休眠状态时,无法移动或调整Form1窗口的大小
//正在运行,因为UI线程被阻止。
公共异步任务WaitSynchronously()
{
//添加System.Threading的using指令。
睡眠(10000);
返回“完成”;
}
我已经读到:当逻辑流到达等待令牌时,调用线程将被挂起,直到调用完成

你在哪里读到这些废话的?要么你没有引用某些上下文,要么你应该停止阅读包含这些内容的任何文本。等待的重点是做与之相反的事。等待的要点是在异步任务运行时保持当前线程执行有用的工作

更新:我下载了你引用的那本书。那部分的一切都是错的。扔掉这本书,买一本更好的书

我不明白的是,当我点击按钮时,label1将运行文本,标签将在10秒钟后才有相同的文本,但在这10秒钟内,我能够在我的文本框中输入文本,因此似乎主线程正在运行

没错。下面是发生的情况:

        label1.Text = Thread.CurrentThread.ThreadState.ToString();
文本已设置

        button1.Text =  await DoWork();
这里发生了很多事情。先发生什么<调用代码>DoWork
。它有什么作用

        return Task.Run(() => { Thread.Sleep(10000);
它从线程池中抓取一个线程,将该线程置于睡眠状态10秒钟,然后返回一个表示该线程正在完成的“工作”的任务

现在我们回到这里:

        button1.Text =  await DoWork();
我们手头有一项任务。wait first检查任务是否已完成。事实并非如此。接下来,它将此方法的剩余部分注册为任务的继续。然后它返回给它的调用者

嘿,打电话的是什么?我们是怎么到这里来的

一些代码称为此事件处理程序;处理Windows消息的是事件循环。它看到一个按钮被单击并发送到单击处理程序,该处理程序刚刚重新启动
        button1.Text =  await DoWork();
        button1.Text =  await DoWork();