为什么以及如何在等待MVC控制器操作之后维护MVC请求线程状态

本文关键字:MVC 维护 之后 请求 线程 状态 操作 控制器 在等待 为什么 | 更新日期: 2023-09-27 17:57:44

在下面的代码中,在等待调用之前和之后,线程id和_uow(工作单元)的散列是相同的。如果请求线程被释放,为什么继续请求线程具有相同的id?为什么与请求线程关联的_uow对象具有相同的hash id,就像线程状态被维护一样,尽管它被释放到线程池中?

public AccountController(IUow uow)
{
    _uow = uow;
}
public async Task<ActionResult> Sample()
{
    int id1 = Thread.CurrentThread.ManagedThreadId;
    int hash1 = _uow.GetHashCode();
    await SignInAsync(account, isPersistent: false);
    int id2 = Thread.CurrentThread.ManagedThreadId; //same as id1
    int hash2 = _uow.GetHashCode(); //same as hash1
    return Content("");
}

为什么以及如何在等待MVC控制器操作之后维护MVC请求线程状态

在ASP中。NET,不能保证在await之后在同一个线程上。但这并不意味着你一定会在另一个线程上,你仍然可以偶然地回到同一个线程。如果您正在await执行的Task在返回给您时已经完成,那么您也将停留在同一线程上。

_uow字段是另一回事:在这个代码中,它将始终保持不变(假设它不是[ThreadStatic]字段)。这是因为在await之后,您总是返回到相同的this,它不绑定到任何线程。

事实上,这甚至更强:HttpContext.Current(以及与之相关的一切)也将保持不变。这是因为ASP。NET同步上下文将负责将HTTP上下文移动到await之后的任何新线程。

这里有两种情况。

  • SignInAsync已同步执行。请尝试以下操作,看看是否是这样:

    public async Task<ActionResult> Sample()
    {
        int id1 = Thread.CurrentThread.ManagedThreadId;
        int hash1 = _uow.GetHashCode();
        var task = SignInAsync(account, isPersistent: false);
        Debug.Print("completed synchronously: " + task.IsCompleted);
        await task;    
        int id2 = Thread.CurrentThread.ManagedThreadId; //same as id1
        int hash2 = _uow.GetHashCode(); //same as hash1
        return Content("");
    }
    
  • await继续之后,相同的池线程恰好为请求的其余部分提供服务。这是非常不可能的,但仍然是可能的,尽管无论如何你都不应该依赖它。