Differencebetween Await Task<T> and Task<T>.Result

What is the difference between await Task T and Task T .Result?


I wont be wrong if I think that await will release the calling thread but Task.Result will block it, would it be right?

Generally, yes. await task; will "yield" the current thread. task.Result will block the current thread. await is an asynchronous wait; Result is a blocking wait.

There's another more minor difference: if the task completes in a faulted state (i.e., with an exception), then await will (re-)raise that exception as-is, but Result will wrap the exception in an AggregateException.

As a side note, avoid Task.Factory.StartNew. It's almost never the correct method to use. If you need to execute work on a background thread, prefer Task.Run.

Both Result and StartNew are appropriate if you are doing dynamic task parallelism; otherwise, they should be avoided. Neither is appropriate if you are doing asynchronous programming.

Await vs Task.Result in an Async Method

await asynchronously unwraps the result of your task, whereas just using Result would block until the task had completed.

See this explanantion from Jon Skeet.

Task TResult .Result vs await a task


First version

static void Caller()
{
Task<int> test = TestMethod();
int k = test.Result;
Console.WriteLine("k: " + k);
}

In this version the async keyword would be obsolete. This is a synchronous method. The executing thread blocks at test.Result until the task has finished.

Second version

static async Task Caller()
{
Task<int> test = TestMethod();
int i = await test;
Console.WriteLine("i: " + i);
}

This is a (kind of) asynchronous version (it's not really asynchron, it's just a synchronous method run on a different thread). The difference to the first version is that the compiler builds a state machine for this.

So the control flow of the executing thread is returned to the caller of this method when await test is reached.

When the task has finished, the execution of this method is resumed at Console.WriteLine (or more precisely at the assignment to i).

For more information about what the compiler does you can read for example this.


The second version is useful if you have a longer running task that you need to execute from an UI. Since the control is returned to the caller while awaiting the task, the UI thread is not blocked and your application stays responsive.

What's the difference between using .Result inside a Task body and using await in async method?

Since the first example starts a new task on a threadpool thread, calling asynchronous methods is unnecessary, when there are equivalent synchronous methods. It does not have any benefit, it just needlessly add some overhead involved in managing asynchronous tasks. Just use .GetResponse() instead of .GetResponseAsync().Result and .ReadToEnd() instead of .ReadToEndAsync().Result.

await, unlike .Result, doesn't block calling thread

This is not always true. Awaited methods can execute (partially or completely) synchronously, if they decide to do so.

For instance, is there any difference?

There are a bunch of differences between the two examples. Although they may be insignificant in certain contexts, they can be crucial in another:

  1. AggregateException

    When exception occurs in a task or task is cancelled, calling Task.Result will wrap exception in an AggregateException. Contrary, awaiting this task will throw the original exception. So you must be careful when catching specific exception.

  2. Thread

    In the first example, whole method will execute on the same (threadpool) thread. The second example can execute on several different threads, depending on the current SynchronizationContext. Code sensitive to thread-affinity should be avoided.

  3. SynchronizationContext

    First exapmple will execute without SynchronizationContext, while the second will restore original SynchronizationContext after each await. For console applications, this doesn't matter. But in WPF or WinForms applications, UI elements can be accessed only from corresponding synchronization context.

  4. Asynchronous execution

    In the first example, PrintPageAsync will return immediatelly after new task is queued for execution, while the second will execute synchronously up to the first await (or possibly even after that). This can have severe impact on GUI responsivnes, especially when async method uses WebRequest, because GetResponseAsync() method performs DNS resolution synchronously (see How to create HttpWebRequest without interrupting async/await?). So wrapping code in a Task.Run() is recomended, when method that uses WebRequest is called from UI thread.

What's the difference between await (async) Task and await Task?

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

Understanding Task vs Task T as a return type

Task represents an operation which might be in progress, or might have been cancelled, faulted, or completed. A completed Task does not contain any sort of result, it just represents the fact that the operation has finished.

Task<T> also represents an operation which might be in progress, or might have been cancelled, faulted, or might have completed. However, a completed Task<T> will contain the result of that operation, which you can then read.

You can write:

public async Task<IEnumerable<string>> GetAllObjectsNames(string bucketName)
// ...
var objects = await GetAllObjectsNames("Foo");
await GetAllObjectsNames("Foo"); // Throws away the result of the Task

However you can only write:

public async Task GetAllObjectsNames(string bucketName)
// ...
await GetAllObjectsNames("Foo");

The Task returned from this version of GetAllObjectsNames cannot contain a result, so you can only tell when that operation has finished - you cannot get a result out of it.

You might use Task as the return value from an UploadObject method - where you care when the upload operation finishes, but there's no result for you to read. You would probably use Task<T> for GetAllObjectsNames, since the point of that operation is to fetch some values for you to then use.

Conceptually it's the same as the difference between a method which returns void (does not return a result), or a method which returns anything else. Or the difference between Action and Func<T>.

Why use Task.FromResult T (T result) from a method that contains awaits?

According to the best stackoverflow answer I've found about Task.FromResult: https://stackoverflow.com/a/19696462/6440521

The usage of Task.FromResult is appropriate only in the context of synchronous methods and mocking. So using it in an async method when you just want to return a result is redundant - gives you no additional benefits, also AsyncGuidance does not say anything about using Task.FromResult in an async method:
https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md

So AFAIK using Task.FromResult in an async method is unnecessary, bloats your code and gives you no real benefits.

How can I await task in Task T function?


If I change the return type to async List<HWElDocument'>

You need both an async modifier on the method and a Task return type. So this signature should work:

public async Task<List<HWElDocument>> GetHWElDocumentsAsync(int? ProjectID = null)

The async will tell the compiler to internally use an asynchronous state machine and allows you to use the await keyword inside of the method.

And when you want to return something from an asynchronous method, you will need a Task<T> return type. When using async, the compiler also will make sure to wrap your return value in a task automatically, so you can just return the value directly.

So your returning line should also use await in order to await the task from ToListAsync and then the result will be automatically wrapped in your method’s result task:

public Task<List<HWElDocument>> GetHWElDocumentsAsync(int? ProjectID = null)
{
// Get all Items
if (ProjectID == null)
return await database.Table<HWElDocument>().ToListAsync();

// Or all items meeting a condition
else
{
List<HWDocuProj> projList = await database.Table<HWDocuProj>()
.Where( item => item.ProjID == ProjectID)
.ToListAsync();
return await database.Table<HWElDocument>()
.Where(item => projList.Exists(p => p.ProjID == item.ID))
.ToListAsync();
}
}


Related Topics



Leave a reply



Submit