不允许异步锁

Async lock not allowed

基本上,我想向 tcp 服务器发出多个异步请求。我目前有一个工作的客户端,它只是同步的,并且在每次网络调用时都会阻止 UI。由于几乎同时出现多个请求,我尝试这样做:

private object readonly readLock = new object(); 
public async Task UpdateDetailsAsync()
{
    //I want every request to wait their turn before requesting (using the connection) 
    //to prevent a read call from catching any data from another request
    lock (readLock)
    {
        Details details = await connection.GetDetailsAsync();
        detailsListBox.Items = details;
    }
}

我确信这不是 lock 的好用法,但这是我能想到的唯一可以让调用等待轮到它们的方法。有没有我可以用来实现这种行为的对象?我以为 Monitor 会是一样的,所以我没有尝试(我知道它们是多线程的东西,但这就是我所熟悉的......)

看起来你遇到的问题是线程在获取锁时会阻塞,所以你的方法不是完全异步的。要解决此问题,您可以使用 SemaphoreSlim.WaitAsync

private readonly SemaphoreSlim readLock = new SemaphoreSlim(1, 1); 
public async Task UpdateDetailsAsync()
{
    //I want every request to wait their turn before requesting (using the connection) 
    //to prevent a read call from catching any data from another request
    await readLock.WaitAsync();
    try
    {
        Details details = await connection.GetDetailsAsync();
        detailsListBox.Items = details;
    }
    finally
    {
        readLock.Release();
    }
}

这个问题已经被 NuGet package Nito.AsyncEx 巧妙地解决了,截至 2015 年 8 月下载量已超过 50,000。

来自自述文件:

#AsyncEx A helper library for async/await.#

Supports .NET 4.5/4.0, iOS, Android, Windows Store 8.0, Windows Phone Silverlight 8.0/7.5, Windows Phone Applications 8.1, Silverlight 5.0/4.0, and all portable libraries thereof.

[snip]

#AsyncLock#

A lot of developers start using this library for AsyncLock, an async-compatible mutual exclusion mechanism. Using AsyncLock is straightforward:

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(1));
  }
}

在 GitHub 上查看 C# 源代码或安装 NuGet package Nito.AsyncEx.