async/await 的一些知识 (死锁问题)

博文


案例一

在ABP.Zero最近的一次更新中,有这样的修改:

解释的缘由是:
在一个不是异步的方法中返回一个Task, 通常来讲是没有问题的,可是当这段代码被using包裹时,using可能在Task执行完成前就释放。因而租户ID会被恢复为旧值,而再也不是null,致使数据写入数据库时tenantId不对。html

案例二

async Task TestAsync() 
{
    await Task.Delay(1000);
}

andgit

Task TestAsync() 
{
    return Task.Delay(1000);
}

前者相似于Task.Delay(1000).ContinueWith(() = {}),后者就是通常的 Task.Delay(1000)。github

案例三

static async Task TestAsync()
{
    await Task.Delay(1000);
}

private void button1_Click(object sender, EventArgs e)
{
    TestAsync().Wait(); // dead-lock here
}

改为下面这种 non-async版本就不会死锁了(但放弃了异步)数据库

static  Task TestAsync()
{
    return Task.Delay(1000);
}

或将上层方法也改成异步(更好的方案)异步

private async void button1_Click(object sender, EventArgs e)
{
    await TestAsync();
}

死锁的缘由

不管是UI context 仍是 ASP.NET request context都不会和某个特定的线程绑定,可是在同一时间,只有一个线程能够访问它。async

上层方法也改用异步后,则全部等待都是异步等待,上层方法也不会阻塞context线程

相关文章
相关标签/搜索