Zac*_*ach 3 c# thread-synchronization async-await
我们有一个用 C# 目标框架 2.0 编写的旧库。最近我们将在现代 .net core 项目中使用它并打算使用async/await. 然而,旧图书馆有很多lock街区。
我们计划添加新async方法来实现相同的逻辑。
例如,
旧代码
void GetOrder()
{
// ...
lock(_lock)
{
//...
}
}
Run Code Online (Sandbox Code Playgroud)
预期结果
async Task AsyncGetOrder()
{
// ...
await DoSomethingWithLock()
}
Run Code Online (Sandbox Code Playgroud)
请给我一些关于如何翻译lock成 的建议async/await。
有以下几种通用方法:
四处寻找如何编写无锁 C#。有时它涉及对类Interlocked的明智使用。其他时候,它涉及到心态向不可变状态的转变(询问函数式程序员)。在很多情况下,这样做可以显着提高并行性能。
当然,无锁线程安全代码可以同步或异步执行。
这基本上就是人们在推荐 NuGet 包或类似包时所推荐的SemaphoreSlim内容AsyncEx。
斯蒂芬·克利里 (Stephen Cleary) 撰写了有关走这条路线背后的智慧的文章。他还给出了一些如何做到这一点的例子:
https://blog.stephencleary.com/2013/04/recursive-re-entrant-locks.html
Monitor.Lock#3 找到/的异步替代品lock基本上你需要的是同时提供所有这三个功能的东西:
Monitor.Lock/lock给你第二件事和第三件事。所以你想要的东西既能给你第一个,又不牺牲其他两个。
这比看起来有点棘手。乍一看,有几个 NuGet 包似乎可以执行此操作。但我所知道的唯一正确的是这个 NuGet 包(我写的):
https://www.nuget.org/packages/ReentrantAsyncLock/
这是在行动中:
var asyncLock = new ReentrantAsyncLock();
var raceCondition = 0;
// You can acquire the lock asynchronously
await using (await asyncLock.LockAsync(CancellationToken.None))
{
await Task.WhenAll(
Task.Run(async () =>
{
// The lock is reentrant
await using (await asyncLock.LockAsync(CancellationToken.None))
{
// The lock provides mutual exclusion
raceCondition++;
}
}),
Task.Run(async () =>
{
await using (await asyncLock.LockAsync(CancellationToken.None))
{
raceCondition++;
}
})
);
}
Assert.Equal(2, raceCondition);
Run Code Online (Sandbox Code Playgroud)
这当然不是第一次尝试这样做。但正如我所说,这是迄今为止我见过的唯一正确的尝试。其他一些实现会在尝试在其中一个调用中重新输入锁时发生死锁
Task.Run。其他的实际上不会提供互斥,并且
raceCondition变量有时会等于 1 而不是 2: