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

时间:2022-01-17 04:53:04

博文


案例一

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

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

解释的原因是:

在一个不是异步的方法中返回一个Task, 一般来说是没有问题的,但是当这段代码被using包裹时,using可能在Task执行完成前就释放。于是租户ID会被恢复为旧值,而不再是null,导致数据写入数据库时tenantId不对。

案例二

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

and

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

前者类似于Task.Delay(1000).ContinueWith(() = {}),后者就是一般的 Task.Delay(1000)。

案例三

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都不会和某个特定的线程绑定,但是在同一时间,只有一个线程可以访问它。

上层方法也改用异步后,则所有等待都是异步等待,上层方法也不会阻塞context