web-dev-qa-db-ja.com

非同期メソッドでのセマフォ待機とWaitAsync

この種のコンテキストで使用される、SemaphoreSlimでのWaitとWaitAsyncの使用の違いを調べようとしています。

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;
}
8
mo5470

Asyncメソッドがある場合は、可能であれば呼び出しのブロックを回避する必要があります。 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などの他のそのような構造とは異なります) 。

14
Evk

違いは、Waitはセマフォが解放されるまで現在のスレッドをブロックしますが、WaitAsyncはブロックしないことです。

5
the_joric