同一个函数内多个异步锁

通常,使用异步锁都是直接使用这个库 AsyncEx 中的 AsyncLock

先看看官方栗子:

private readonly AsyncLock _mutex = new AsyncLock();
public async Task UseLockAsync()
{
  // AsyncLock can be locked asynchronously
  using (await _mutex.LockAsync())
  {
    // It's safe to await while the lock is held
    await Task.Delay(TimeSpan.FromSeconds(10));
  }
}

这个栗子的效果是如果有很多用户同时访问进来,里面的内容会 one by one 执行,不会出现同时执行的情况。

假设有这样一个情况, 里面的逻辑内容是针对某个用户的。

private readonly AsyncLock _mutex = new AsyncLock();

public async Task SomeFunAsync(string userId)
{
  // AsyncLock can be locked asynchronously
  using (await _mutex.LockAsync())
  {
	// It's safe to await while the lock is held
	await Task.Delay(TimeSpan.FromSeconds(10));
	// do something for user id.
  }
}

希望里面的内容只针对同一个用户访问的时候,不允许同时操作。比如,对用户的余额操作。

解决方法是对不同的 user 创建不同的 AsyncLock 。 如下:

static readonly ConcurrentDictionary<string, Lazy<AsyncLock>> _mutexs = new ConcurrentDictionary<string, Lazy<AsyncLock>>();

public async Task SomeFunAsync(string userId)
{
   var _mutex = _mutexs.GetOrAdd(userId, (_) => new Lazy<AsyncLock>(() => new AsyncLock())).Value;

  // AsyncLock can be locked asynchronously
  using (await _mutex.LockAsync())
  {
	// It's safe to await while the lock is held
	await Task.Delay(TimeSpan.FromSeconds(10));
	// do something for user id.
  }
}

使用 ConcurrentDictionary<string, Lazy<AsyncLock>> 并发字典和懒加载来获取每个用户的 AsyncLock

已禁用评论。