-5

What is the difference betweeen await an async Task or await a simple Task?

A sample code for better undestanding my dubt:

WEBAPI-CALL:

public async Task<IHttpActionResult> GetFiles()
{
   //Simple call for clean code, i think
   var t = DownloadFile(1);
   return Ok(await t);
}

CASE A:

public static async Task<File> DownloadFile(int fileId){
  //Some checks if i can download the file

  //Some other checks if the file exist

  return await TakeFile(fileId);
}

CASE B:

//In this case i can use ref and out parameters and await the task!

public static Task<File> DownloadFile(int fileId){
  //Some checks if i can download the file

  //Some other checks if the file exist

  var t = Task.Run(() => TakeFile(fileId));
  t.Wait();
  return Task.FromResult(t.Result);
}

Where is the difference in terms of performance/hangs?

EDIT: I use only async code called in different ways

Im Flash
  • 45
  • 1
  • 8
  • *Where is the difference in terms of performance/hangs* is the wrong question here. These are doing totally different things, especially "B" which creates a new thread. – Liam Oct 31 '17 at 11:54
  • I edited the post for better understanding. I don't get "These are doing totally different things". Isn't the result the same? **EDIT: is not a duplicate, in fact i work only with tasks and the entry point is always async** – Im Flash Oct 31 '17 at 11:58
  • 3
    Case B is something that shouldn't ever occur in production code, as it actually executes code synchronously with a bunch of needless task wrapping. Despite the superficially similar names, `Task.Wait` and `await` are completely different things. The former waits synchronously for a task to complete and should rarely if ever be used, the latter is how you get the result of a task within an `async` block. – Jeroen Mostert Oct 31 '17 at 11:58
  • 2
    Your missing some fundamental knowledge. You need to understand the difference between a Task/Thread and asynchronous code (they are not the same thing) as well as blocking vs non-blocking code. – Liam Oct 31 '17 at 12:08
  • @JeroenMostert Thank you for you explaination. How you write it? – Im Flash Oct 31 '17 at 12:08
  • @Liam Thank you. I will search more information about Tasks and Async Code. Have you some good article that i can read (like MSDN or something else)? – Im Flash Oct 31 '17 at 12:10
  • 3
    I have no idea, since you have a method called `GetFiles` that returns something, calls to a method called `TakeFile` that isn't specified anywhere, and you lack an actual statement of what *problem* you have. That makes it hard to say what code, if any, needs to be written. – Jeroen Mostert Oct 31 '17 at 12:10
  • @JeroenMostert Actually i don't have any problem in either case. I am trying to undestand the difference between the first case vs the second case and why i should't use the latter instead of the former. I read a lot of articles in past but at the moment i don't get the difference – Im Flash Oct 31 '17 at 12:17
  • 2
    @ImFlash Reference [Async/Await - Best Practices in Asynchronous Programming](https://msdn.microsoft.com/en-us/magazine/jj991977.aspx) – Nkosi Oct 31 '17 at 12:18
  • @Nikosi thank you! – Im Flash Oct 31 '17 at 12:20
  • [Stephen Cleary has some good articles on the subject](https://blog.stephencleary.com/) try [this one](https://blog.stephencleary.com/2012/02/async-and-await.html) – Liam Oct 31 '17 at 12:50
  • Also try the [async/await FAQ](https://blogs.msdn.microsoft.com/pfxteam/2012/04/12/asyncawait-faq/) on MSDN – Liam Oct 31 '17 at 12:53

1 Answers1

1

Case B is not async-await.

If you have a thread, and this thread has to start a fairly lengthy process in which it has nothing to do but wait, usually because someone / something else performs the operation, then your thread could decide to do something else instead of waiting for the operation to finish.

Typical operations for this are writing data to a disk, asking for an internet page, doing a database query, etc. On a very low level, your thread can't do anything but wait for the operation to complete.

For instance when writing data to a file, your thread's world ends when it orders the hardware to write the data. Your thread doesn't have to move the write-arm in the hard disk, wait until the correct sector is under the write-arm, send the write signals etc. Your thread can't do anything but wait for completion.

During this time, your thread could start doing something else, and when it has time, it can check if the write operation is finished, and execute the statements after the write operation.

This scenario is described in a kitchen analogy in this interview with Eric Lippert. where a cook doesn't wait for the tea water to boil, but starts slicing the bread. Search somewhere in the middle for async-await

Whenever you call an async function, you can be certain there is an await. In fact, your compiler complains if you write an async function but forget to await somewhere in it.

Whenever your thread enters the async function, it continues working until it sees the await. This indicates that the thread should not perform the statements after the await before the Task that is awaited for is finished and returns.

Normally your thread wouldn't do anything. But in async-await your thread goes up its call stack to perform the functions after the call until it sees the await. It goes up the call stack again, to peform functions until it sees an await, etc.

After everyone is awaiting, the thread can't do anything anymore and is returned to the thread pool. If the process that we were awaiting for (the hard disk write) is finished, a thread is fetched to the thread pool. This thread will continue performing the statements after the await until it sees an await again.

This is described in the article by Stephen Cleary: There is no thread

Quite often you'll see an await immediately after the async-call:

var fetchedItems = await stream.ReadAsync();

In this case the await is immediately after the call. The thread won't do much in this function before ReadAsync is finished.

But sometimes your function doesn't need the result immediately:

var fetchTask = stream.ReadAsync()
// because there is no await, instead of doing nothing the thread can do the following:
DisplayWaitIcon();
CalculateSomething();

// now the thread needs the result. So it starts awaiting:
var fetchedItems = await fetchTask;
// here we know that the ReadAsync is finished,
// and the returned items are available in fetchedItems.
ProcessFetchedItems(fetchedItems);

You see that in my story there is only one thread that is doing all the stuff. If you look closely, it doesn't have to be the same thread that does all the stuff, it might be a different thread.

This can be seen in a debugger, if you investigate the ThreadId. This other thread has the 'context` of the original thread, with the effect that it can act as if it was the original thread. You don't have to worry about multi-threading, mutexes, race conditions etc. For the designer of the program it is as if one thread does all the stuff.

Case B however is not async await. Here you order a thread from a pool of available threads to do something. In the meanwhile your thread is free to do other things until it waits for the task performed by the other thread to completes. Because your function is not async, whenever your thread starts waiting, it doesn't go up its call stack to see if it can do something else, it really waits and does nothing until the task is completed.

This article about async-await written by the ever so helpful Stephen Cleary helped me a lot to understand how to use async-await

Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116