Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async/Await VS Task.Run : When to use ? How to use?

Okay I hope I got the basics of async/await but still some questions a re lingering in my head.

But now it is the problem I am talking about . Suppose in this simple example

static void Main(string[] args)
{

    Method();

    Console.WriteLine("Main Thread");

    Console.ReadLine();

}

public async static void Method()

{

    await Task.Run(new Action(LongTask));

    Console.WriteLine("New Thread");

}

public static void LongTask()

{

    Thread.Sleep(8000);

    Console.WriteLine("Long Task");

}

The main thread still continues and prints Main Thread after calling Method() and encountering an await for 8 seconds .

So accordingly the Method() returns to the caller i.e. to the main function here once it encounters await , saves the synch context and keeps on executing from there .

It prints Main Thread first .

Then after 8 seconds complete , Long Task and then New Thread get printed.

This part I got . My question is in my application :

public IList<createcaseoutput> createCase(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)    
{
    .............
    SQL.CaseSQL.getCreateCaseParameters(CreateCaseInput, out strSPQuery, out listParam);    
    var AcctLst = rep.ExecuteStoredProcedure<createcaseoutput>(strSPQuery, listParam).ToList();

    if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))

    {
        await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
    }

    console.writeline("Async called");
    return AcctLst;    
}

public async Task<ilist<savecasesearchoutput>> saveCaseSearch(SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key)

{
    ..........................
    SQL.CaseSQL.getSaveCaseSearchParameters(SaveCaseSearchInput, case_key, out strSPQuery, out listParam);

    var AcctLst = await rep.ExecuteStoredProcedureAsync<entities.case.savecasesearchoutput>(strSPQuery, listParam);

    return AcctLst;
}

Here also createCase is encountering await and it should return immediately right and execute the very next line itself and print Async called before even the SaveCaseSearch completes right ?

Okay if I am thinking loud it might be control returns to the caller .

So is it like if I wrap my call SavCaseSearch inside another async/await method named suppose

async DoWork() {....
}

and call this DoWork() from CreateCase() directly so then

It will go on printing "Async called" once call to DoWork() encounters await and before it even completes ?

Am I thinking in the correct way ?

Also sometimes I see and get confused between

await someAsync() 

and

await Task.Run(() => someAsync()) ..

what's the difference between them ? and which one to follow ?

like image 259
StrugglingCoder Avatar asked Apr 15 '16 17:04

StrugglingCoder


People also ask

What is the difference between Task run and async await?

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. The async and await keywords don't cause additional threads to be created.

When should you use async await?

Inside an async function, you can use the await keyword before a call to a function that returns a promise. This makes the code wait at that point until the promise is settled, at which point the fulfilled value of the promise is treated as a return value, or the rejected value is thrown.

Is Task run asynchronous?

In . NET, Task. Run is used to asynchronously execute CPU-bound code.

Can we use async without Task?

Async code can be used for both I/O-bound and CPU-bound code, but differently for each scenario. Async code uses Task<T> and Task , which are constructs used to model work being done in the background. The async keyword turns a method into an async method, which allows you to use the await keyword in its body.


2 Answers

My question is in my application :

Your code won't compile because you're using await without async. Corrected code would be:

public async Task<IList<createcaseoutput>> createCaseAsync(CreateCaseInput CreateCaseInput,SaveCaseSearchInput SaveCaseSearchInput)    
{
  ...
  await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
  console.writeline("Async called");
  return AcctLst;    
}

Here also createCase is encountering await and it should return immediately right and execute the very next line itself and print Async called before even the SaveCaseSearch completes right ?

No. This code:

  await saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);

is the same as this code:

  var saveTask = saveCaseSearchAsync(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
  await saveTask;

So, first, createCaseAsync would call saveCaseSearchAsync. Presumably, saveCaseSearchAsync is performing some asynchronous operation, so it will return an incomplete task to createCaseAsync. createCaseAsync then awaits that task, which causes it to return an incomplete task to its caller.

Eventually, saveCaseSearchAsync will complete, which will complete the task it returned (which I called saveTask in the code above). This in turn will continue executing createCaseAsync, and it will proceed to the next line and print "Async called" on the console.

So is it like if I wrap my call SavCaseSearch inside another async/await method

You wouldn't need a wrapper because createCaseAsync is already returning a Task.

what's the difference between them ? and which one to follow ?

Task.Run is mainly for pushing blocking work off the UI thread and onto the threadpool. Since you're on ASP.NET, don't use Task.Run.

like image 80
Stephen Cleary Avatar answered Sep 30 '22 18:09

Stephen Cleary


The first rule of async is to always use async or never use async.

If your underlying API can't handle async it's no use to use async in the upper layers (like ASP.NET MVC), since at some point you'll get thread starvation as all threads are occupied waiting on IO operations (like DB calls).

Your example is a classical case where you mix sync and async. The Sleep call will lock the thread until it completes. You should have used Task.Delay instead as it would have released the thread until the delay completes.

My advice to you is to simply start by following the rule I mentioned first and only when IO bound operations like DB or file calls are involved. Then when you understand async better you can start to break it since you then have a much better understanding in what it can lead to.

(Sorry for not answering your questions directly, but threading is a complex topic and your brain can fry if you try to get it all in directly. Start small.)

like image 29
jgauffin Avatar answered Sep 30 '22 20:09

jgauffin