I am trying to get my head around async/await and thought I did understand few things about the usage. But still not quite clear what would be the actual benefit in a scenario like below.
Look at the Task.Run usage. The first method uses a normal delegate and uses Thread.Sleep but the second one uses 'async' delegate and Task.Delay.
My question is : how does this make any difference to this method (or it does not) ?
The method itself is an async method. The code is creating a separate thread (via Task.Run) and this thread has nothing else to do other than executing that delegate. So, even if it yields with an await on Task.Delay, what is the use in this scenario, since the thread is anyways a isolated thread not used for anything else and even if it just uses Thread.Sleep, the thread would still context switch to yield to other threads for the processor.
// The task thread uses a async delegate
public async Task<bool> RetrySendEmail(MailMessage message)
{
bool emailSent = false;
await (Task.Run(***async ()*** =>
{
for (int i = 0; i < 3; i++)
{
if (emailSent)
break;
else
// Wait for 5 secs before trying again
***await Task.Delay(5000);***
try
{
Smtphost.Send(message);
emailSent = true;
break;
}
catch (Exception e) { emailSent = false; // log; }
}
return emailSent;
}));
}
// The task thread uses a normal delegate
public async Task<bool> RetrySendEmail(MailMessage message)
{
bool emailSent = false;
await (Task.Run(***()*** =>
{
for (int i = 0; i < 3; i++)
{
if (emailSent)
break;
else
// Wait for 5 secs before trying again
***Thread.Sleep(5000);***
try
{
Smtphost.Send(message);
emailSent = true;
break;
}
catch (Exception e){ emailSent = false; // log; }
}
return emailSent;
}));
}
Async methods are intended to be non-blocking operations. An await expression in an async method doesn't block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.
with async / await , you write less code and your code will be more maintainable than using the previous asynchronous programming methods such as using plain tasks. async / await is the newer replacement to BackgroundWorker , which has been used on windows forms desktop applications.
Delegates enable you to call a synchronous method in an asynchronous manner. When you call a delegate synchronously, the Invoke method calls the target method directly on the current thread. If the BeginInvoke method is called, the common language runtime (CLR) queues the request and returns immediately to the caller.
NET, Task. Run is used to asynchronously execute CPU-bound code. Let's say there is a method which does some CPU-bound work. Example : looping through a large array and doing some complex computation on each element of the array. For such a case, Task.
My question is : how does this make any difference to this method (or it does not) ?
A couple of differences
async
delegate inside Task.Run
means that you actually run a Task<Task>
. This is hidden from you by the fact that Task.Run
is async aware and unwraps the inner task for you, something that Task.Factory.StartNew
didn't doWhen you use an async delegate with Task.Run
, you create a new thread, then yield control once you hit await Task.Delay
. The continuation will run on an arbitrary thread-pool thread. Additionaly, the delegate is transformed into a state-machine by the compiler.
With the normal delegate, you create a thread, synchronously block it for 5 seconds, and then continue at the point you left off. No state-machines, no yielding.
So, even if it yields with an await on Task.Delay, what is the use in this scenario, since the thread is anyways a isolated thread not used for anything else and even if it just uses Thread.Sleep, the thread would still context switch to yield to other threads for the processor.
The use of async
with Task.Run
can be when you want to do both CPU and IO bound work, all in a dedicated thread. You're right in thinking that after the async delegate yields, it returns on an arbitrary thread. Though, if you hadn't used Task.Run
, and the async
method executed from a thread that had a custom synchronization context attached (such as WinformsSynchronizationContext), any work after the await
would yield back to the UI message loop, unless you used ConfigureAwait(false)
.
To tell the truth, I haven't seen that many scenarios where Task.Run
and async
are used correctly. But it does make sense at times.
The difference is that you are wasting a thread and its allotted time-slice.
When you block a thread for 5 seconds that thread can't be used in other parts of your system to do actual CPU work. It also creates a context switch as that thread can't do anything else.
When you free that thread by using Task.Delay
instead of Thread.Sleep
the thread can return to the ThreadPool
, take a waiting task and execute it.
Over all when you free your threads when you can you make your application more scalable and efficient as it needs less resources to do the same work or the same amount of resources to do more work.
When your operation is really asynchronous there's no need to use Task.Run
(unless you need a background thread). You can just call that method and await the returned task:
public async Task<bool> RetrySendEmail(MailMessage message)
{
bool emailSent = false;
for (int i = 0; i < 3; i++)
{
if (emailSent)
break;
else
await Task.Delay(5000);
try
{
Smtphost.Send(message);
emailSent = true;
break;
}
catch (Exception e) { emailSent = false; // log; }
}
return emailSent;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With