C# 当异步代码试图在已经执行的线程上恢复时会发生什么情况?

C# 当异步代码试图在已经执行的线程上恢复时会发生什么情况?,c#,.net,multithreading,asynchronous,C#,.net,Multithreading,Asynchronous,我觉得这个问题的答案是因为我对线程的工作方式有一个错误的概念,但这里是 private void button1_Click(object sender, EventArgs e) { this.TestMethodAsync(); // No await, i.e. fire and forget // ** Some code here to perform long running calculation (1) ** } private async Task TestMe

我觉得这个问题的答案是因为我对线程的工作方式有一个错误的概念,但这里是

private void button1_Click(object sender, EventArgs e)
{
  this.TestMethodAsync();   // No await, i.e. fire and forget

  // ** Some code here to perform long running calculation (1) **
}

private async Task TestMethodAsync()
{
  // Some synchronous stuff

  await Task.Delay(1000);

  // ** Some code here to perform long running calculation (2) **
}
首先,我不会“触发并忘记”像这样的异步方法(我会使用Task.Run),但我遇到过这样的代码,我正试图理解它的效果

在使用
WindowsFormsSynchronizationContext
的WinForms应用程序中,我对async和await的理解告诉我,当我单击按钮1时,该方法将在UI线程上同步启动。它将调用
TestMethodAsync
并同步运行,直到到达wait。然后它将捕获上下文,启动
任务。延迟
任务,并将控制权交给调用方。由于我们没有等待此调用,
按钮1\u单击
将在UI线程上继续并开始执行计算(1)

在某个时刻,
任务。延迟(1000)
将完成。然后,继续将使用捕获的上下文运行
TestMethodAsync
方法的其余部分,在本例中,这意味着继续将在UI线程上运行。现在将开始执行计算(2)

现在,我们有两个独立的代码部分希望同时在同一个线程(UI线程)上运行。我对这一点的研究似乎表明线程在两段代码之间来回切换,以便同时执行这两段代码

问题:

我对这里到底发生了什么感到困惑。如何在已经运行其他代码的线程上恢复?是什么迫使线程在要运行的两段代码之间切换?通常,当您尝试在已经运行其他代码的线程上恢复时会发生什么情况

(我想这与我的点击事件在UI线程上运行的方式没有什么不同,因为我知道它在UI线程上运行,我知道UI线程也在做其他事情,但我以前没有这样想过。)

如何在已经运行其他代码的线程上恢复

它需要专门设计来支持它。需要有一个适当的框架,允许线程进行工作,然后在稍后的某个时间点执行该工作

这就是UI线程的工作方式。它有一个队列,每当您计划在UI线程中完成的工作时,您都会将一个项目添加到队列的末尾。然后UI线程从队列中获取第一个项目,执行它,然后在完成后继续执行下一个项目,依此类推,直到您结束应用程序

是什么迫使线程在要运行的两段代码之间切换

没什么,因为它不会那样做。它运行一个,然后当它完成时,它运行另一个

通常,当您尝试在已经运行其他代码的线程上恢复时会发生什么情况

要么有人编写了一些定制代码专门用来做这件事,在这种情况下,它会做代码特别要求它做的任何事情,要么你不能

如何在已经运行其他代码的线程上恢复

它需要专门设计来支持它。需要有一个适当的框架,允许线程进行工作,然后在稍后的某个时间点执行该工作

这就是UI线程的工作方式。它有一个队列,每当您计划在UI线程中完成的工作时,您都会将一个项目添加到队列的末尾。然后UI线程从队列中获取第一个项目,执行它,然后在完成后继续执行下一个项目,依此类推,直到您结束应用程序

是什么迫使线程在要运行的两段代码之间切换

没什么,因为它不会那样做。它运行一个,然后当它完成时,它运行另一个

通常,当您尝试在已经运行其他代码的线程上恢复时会发生什么情况


要么是有人编写了一些定制代码专门用来做这件事,在这种情况下,它会做代码特别要求它做的任何事情,要么就是你不能做的事情。

这是你不明白的秘密:我给你Windows消息循环

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    BOOL bRet;
    while(TRUE)
    {
        bRet = GetMessage(&msg, NULL, 0, 0);
        if (bRet <= 0) break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
int-WINAPI-WinMain(HINSTANCE-HINSTANCE、HINSTANCE-hPrevInstance、LPSTR-lpCmdLine、int-nCmdShow)
{
味精;
布尔布雷特;
while(TRUE)
{
bRet=GetMessage(&msg,NULL,0,0);

如果(bRet这是您不了解的秘密:我给您Windows消息循环

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    MSG msg;
    BOOL bRet;
    while(TRUE)
    {
        bRet = GetMessage(&msg, NULL, 0, 0);
        if (bRet <= 0) break;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
int-WINAPI-WinMain(HINSTANCE-HINSTANCE、HINSTANCE-hPrevInstance、LPSTR-lpCmdLine、int-nCmdShow)
{
味精;
布尔布雷特;
while(TRUE)
{
bRet=GetMessage(&msg,NULL,0,0);

如果(b)我对此的调查似乎表明线程在两段代码之间来回切换以执行这两段代码。您不正确。(2)只有在(1)完成后才会启动。@bornfromanegg如果是(这不太可能)然后它在做一些你声称它在做的事情以外的事情,比如在你说的代码中等待一个异步操作是同步的。你是一个工作者。如果你正在执行另一个任务,你如何恢复一个你以前停止工作的任务?是的,你必须记住继续。现在,假设你重新开始继续你的任务:如果你在你的当前任务上工作的话,你是如何执行一个以前的任务的延续的?你在烤面包机上放了一些烤面包片;当你在等着看报纸,付账单时,哦,烤面包片突然出现了。如果你正在付账,你会停止你的一切吗?你在做什么,去给烤面包涂黄油,还是在心里记下你需要给烤面包涂黄油