Tl;Dr
Should you use async
or not depends on whether this code is blocking or not. If it is blocking and you can't make it unblocking then don't use async
and you'll just have to deal with the blocking code. If you can make it non-blocking, using async
then do so. Adding threads (using Task.Run()
not Thread
) depends on what this code is doing, is it IO or CPU bound?
If this code is blocking and you can't change that then the correct implementation would be:
public void MyMethod()
{
// Long running operation
}
In fact if your code is blocking and contains no await
calls, this is exactly what the pre-compiler will turn your method into (async
or not).
Generally if your using async
then always use the Task
class (and it's methods) as this adds a layer of abstraction over the underlying threads and enables the async
pattern. TBH use Task
pretty much all the time, it's rare you need to interact with a thread directly since TPL. In code reviews I basically reject anyone using Thread
now and tell them to use Task
instead.
The correct way to simulate a delay in an async
method is to use Task.Delay()
, so:
public async Task MyMethod()
{
await Task.Delay(10000).ConfigureAwait(false); // Simulates long running operation
}
This will release the thread back into the thread pool while the delay is happening. Your current method blocks the main thread so is less optimised than it could be. ConfigureAwait(false)
just adds some more optimisation around context switching (this depends on your context here so read that link).
This method is the worst of both worlds:
public async Task MyMethod()
{
await Task.Run(() => Thread.Sleep(10000)); // Simulates long running operation
}
this now releases the main thread (good I guess) but all it does is create a new one (with all the overhead of context switching) which then blocks. So you're still using one thread, this thread is still blocked but now you've just added a load of extra context switching into the mix to slow everything down. So this is very inefficient.