AsyncEx.AsyncLock与Scott Hanselman的AsyncLock运行时差异对比
假设我们只关注两款实现的核心异步锁逻辑(排除AsyncEx的扩展功能如可重入锁、超时配置等),二者在运行时的主要差异集中在以下几个方面:
等待队列调度与上下文控制
Stephen Toub的实现(Hanselman版本)依赖TaskCompletionSource队列,锁释放时按顺序唤醒下一个等待任务,默认会捕获当前的SynchronizationContext(比如UI线程上下文),临界区代码会回到原上下文执行。若要避免上下文捕获,只能通过await lock.LockAsync().ConfigureAwait(false)手动控制,实现本身没有内置的调度器配置选项。
AsyncEx的核心实现则内置了TaskScheduler支持,即使不启用额外功能,也可以通过构造函数指定调度器(比如TaskScheduler.Default)来跳过上下文捕获,底层唤醒逻辑对任务执行环境的控制更灵活。锁状态管理与容错逻辑
Toub的实现结构极简,用SemaphoreSlim+队列实现核心逻辑,对锁状态的检查(比如重复释放、异常下的状态一致性)处理较为基础,仅覆盖常规场景。
AsyncEx的实现对锁状态的校验更严谨,释放锁时会处理ObjectDisposedException等边缘情况,且对持有锁的合法性检查更严格,能降低因错误使用导致的死锁或状态紊乱风险。内存与性能开销
Toub的实现只有必要的核心字段(信号量、等待队列、持有标志),内存占用极低,高并发场景下因为逻辑简洁,性能开销也最小。
AsyncEx的实现即便不启用扩展功能,类结构中仍包含用于扩展的预留字段(如取消令牌支持、调度器引用),内存开销略高于前者。不过这种差异在绝大多数业务场景下可忽略,仅在极端高并发的压力测试中可能显现微小性能差距。释放器的实现细节
两款实现均返回IDisposable对象用于释放锁,但AsyncEx的释放器实现更健壮,比如会验证释放操作是否由持有锁的任务触发,避免非法释放;而Toub的实现仅做基础的状态检查,容错性稍弱。
内容的提问来源于stack exchange,提问作者cremor

