Are executions of methodX()
in these two snippets different?
SemaphoreSlim _locker
, .Wait()
, and WaitAsync()
are examples of the same method having either a synchronous and asynchronous version:
A:
SemaphoreSlim _locker = new SemaphoreSlim(1);
async Task methodX()
{
_locker.Wait();
// .. rest of the code
}
B:
SemaphoreSlim _locker = new SemaphoreSlim(1);
async Task methodX()
{
await _locker.WaitAsync();
// .. rest of the code
}
The interesting question is what happens if we can't acquire the lock immediately?
With the first code-sample, the current thread will block, and will become unblocked to continue when the lock becomes acquired, continuing without a thread transition.
With the second code-sample, the
await
will detect the incomplete state, and use a state machine to attach a continuation to happen when the operation completes, and then unroll itself. Assuming that unroll gets to whatever is driving the threads (usually the thread pool), that thread can then be reused to do other CPU work. At some future point, the continuation will be triggered and the work will reactivate, quite possibly on a different thread (sync-context might mean that the same thread gets used, in particular in UI environments like WinForms).This continuation machinery has some (small) overheads - nothing comes for free, but it means that you shouldn't run out of threads; as such
await
is incredibly useful to prevent all your threads on a high-concurrency server being idle, waiting on things like IO, lock acquisition, etc - so that some useful work can still be done.