异步方法中的信号量等待与 WaitAsync

Semaphore Wait vs WaitAsync in an async method

我试图找出在这种上下文中使用的 Wait 和 WaitAsync 的 SemaphoreSlim 之间的区别:

private SemaphoreSlim semaphore = new SemaphoreSlim(1);
public async Task<string> Get()
{
   // What's the difference between using Wait and WaitAsync here?
   this.semaphore.Wait(); // await this.semaphore.WaitAsync()

   string result;
   try {
     result = this.GetStringAsync();
   }
   finally {
     this.semaphore.Release();
   }

   return result;
}

区别在于Wait会阻塞当前线程直到信号量被释放,而WaitAsync不会。

如果您有异步方法 - 您希望尽可能避免任何阻塞调用。 SemaphoreSlim.Wait() 是阻塞调用。那么如果你使用 Wait() 并且此时信号量不可用会发生什么?它会阻塞调用者,这对于异步方法来说是非常意想不到的事情:

// this will _block_ despite calling async method and using await
// until semaphore is available
var myTask = Get();
var myString = await Get(); // will block also

如果您使用 WaitAsync - 如果此时信号量不可用,它不会阻止调用者。

var myTask = Get();
// can continue with other things, even if semaphore is not available

此外,您还应注意将常规锁定机制与 async\await 一起使用。这样做之后:

result = await this.GetStringAsync();

您可能在 await 之后在另一个线程上,这意味着当您尝试释放您获得的锁时 - 它可能会失败,因为您试图从您获得它的同一个线程中释放它。请注意,这是 NOT 信号量的情况,因为它没有线程亲和性(不同于其他此类构造,如 Monitor.EnterReaderWriterLock 等)。