10

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 ?

Bradley Uffner
  • 16,641
  • 3
  • 39
  • 76
StrugglingCoder
  • 4,781
  • 16
  • 69
  • 103
  • 1
    If you are trying to use `async` in a console application, you may run in to problems unless you set it up correctly, it may not behave as expected otherwise. See http://anthonysteele.co.uk/async-and-await-with-console-apps and http://blogs.msdn.com/b/pfxteam/archive/2012/01/20/10259049.aspx – Bradley Uffner Apr 15 '16 at 18:04
  • `async` is [not about threads](http://stackoverflow.com/q/17661428/11683). – GSerg Apr 15 '16 at 18:13
  • Check out Stephen Cleary post about it. Very useful – Ian Apr 15 '16 at 18:33

4 Answers4

4

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.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
3

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.)

jgauffin
  • 99,844
  • 45
  • 235
  • 372
1

Regarding the difference between async/await and Tasks...

Async/Await are syntactic keywords to simplify your code, as everything before the await keyword happens in the calling thread and everything from the await onward happens is in the task's continuation.

Setting this up with tasks using the TPL will require a lot of code and readability suffers. Note however, Underneath it is still using Tasks and Continuations.

Further, they cannot always be used in place of Tasks like when the completion of Task is nondeterministic, or if you have multiple levels of Tasks along with the usage of TaskCompletionSource.

For more information read the chapter 4 "Asynchronous Programming" in the book "Writing High-Performance .NET Code" by Ben Watson

Note also, Internally, the TPL uses the .NET thread pool, but does so more intelligently, by executing multiple Tasks on the same thread sequentially before returning the thread back to the pool. It can do this via intelligent use of delegate objects.

Vicky
  • 1,107
  • 2
  • 13
  • 25
1

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 ?

This shouldn't even compile. The 'await' operator can only be use within an 'async' method. That said, if you remove the 'await' operator, then the next line will print "Async called" before even the saveCaseSearch completes.

Am I thinking in the correct way ?

saveCaseSearch is already an 'async' method, so you don't need to wrap it to achieve the desired result. That said, you could wrap it in another method, if you really want to.

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

The 'await' operator wait for a Task object so either one is fine. I would chose await someAsync(), because it's less code to write.

tchau.dev
  • 903
  • 1
  • 11
  • 30