Why use async and await with Task<>? - c#

If I have a normal method that I want to make asynchronous:
public int Foo(){}
I would do:
public Task<int> FooAsync(){
return Task.Run(() => Foo());
}
Why would I do:
public async Task<int> FooAsync(){
return await Task.Run(() => Foo());
}
The way I plan to use this is:
FooAsync().ContinueWith((res) => {});
I want the method to just run without stopping, but I want something like a callback to be fired, hence the ContinueWith. But with the second version, is there a point to using it?

In my understanding, you only need async and await when you write a method which does some async calls inside, but you would like it to look like it doesn't. In other words you want to write and read code as if it was some normal sequential code, handle exceptions as if it was normal sequential code, return values as if it was normal sequential code and so on. Then compiler's responsibility is to rewrite that code with all the necessary callbacks preserving the logic.
Your method is so simple I don't think it needs that rewriting at all, you can just return the task, but whoever consumes it may want to await for its return value.

Why would I do:
public async Task<int> FooAsync()
{
return await Task.Run(() => Foo());
}
You wouldn't. Your previous version returns Task which is already awaitable. This new version doesn't add anything.
The way I plan to use this is:
FooAsync().ContinueWith((res) => {});
I want the method to just run without stopping, but I want something like a callback to be fired, hence the ContinueWith.
This is where the difference comes in. Let's flesh out your example a little bit:
void DoAsyncStuff()
{
FooAsync().ContinueWith((res) => { DoSomethingWithInt(res.Result) });
}
Using async, you can write the same code like this:
void async DoAsyncStuff()
{
int res = await FooAsync();
DoSomethingWithInt(res);
}
The result is the same. The await keyword turns the rest of your method into a continuation which gets resumed after FooAsync produces a value. It's just like your other code, but easier to read. *shrug*

Related

Should I be using await inside my Task.Run()?

** I've summarised this question at the bottom with an edit **
This has been asked before but I think my circumstances are different.
I am processing multiple requests simultaneously.
This is my code to do that, it runs in a loop. I've removed a bit of code that handles the taskAllocated variable for brevity.
while (!taskAllocated)
{
lock (_lock)
{
// Find an empty slot in the task queue to insert this task
for (i = 0; i < MaxNumTasks; i++)
{
if (_taskQueue[i] == null)
{
_taskQueue[i] = Task.Run(() => Process());
_taskQueue[i].ContinueWith(ProcessCompleted);
break;
}
}
}
}
Process is a typical async Task Process() { CpuIntensiveStuff(); } method.
I've been running the above code, and it has been working fine. It multithreads nicely. Whenever an item comes in, it will find an empty slot in the task queue, and kick it off. When the task completes, the ProcessCompleted method runs, and frees up the slot.
But then I thought, shouldn't I be using await inside my Task.Run? Something like:
_taskQueue[i] = Task.Run(async () => await Process());
After thinking about it, I'm not sure. ContinueWith triggers correctly, when the task has completed, so perhaps it's not necessary.
I ask because I wanted to monitor and log how long each task takes to complete.
So Instead of Process(), I would make another method like:
async Task DoProcess()
{
var sw = Stopwatch.StartNew();
Process();
sw.Stop();
Log(sw.ElapsedMilliseconds);
}
And it occurred to me that if I did that, I wasn't sure if I'd need to await Process(); or not, in addition to not knowing if I should await inside the Task.Run()
I'm in a bit of a tizz about this. Can anyone offer guidance?
Edit:
To summarise:
If Somemethod is:
void SomeMethod() { }
Then
Task.Run(() => SomeMethod()); is great, calls SomeMethod on a new 'thread' (not technically, but you know what I mean).
However, my SomeMethod is actually:
async Task SomeMethod() { }
Do you need to do anything special with Task.Run()?
My code, I am not, I am just straight up ignoring that it's an async Task, and that seems to work:
Task.Run(() => SomeMethod()); // SomeMethod is async Task but I am ignoring that
But I'm not convinced that it a) should work or b) is a good idea. The alternative could be to do:
Task.Run(async() => await SomeMethod());
But is there any point? And this is compounded by the fact I want to really do:
Task.Run(() =>
{
someCode();
var x = startTimer();
SomeMethod();
var y = stopTimer();
someMoreCode()
});
but without await I'm not sure it will wait for somemethod to finish and the timer will be wrong.
Things become more clear if you do not use anonymous methods. For example,
Task.Run(() => Process())
is equivalent to this:
Task.Run(DoSomething);
Task DoSomething() {
return Process();
}
Whereas
Task.Run(async () => await Process())
is equivalent to this:
Task.Run(DoSomething);
async Task DoSomething() {
await Process();
}
In most cases, there is no functional difference between return SomethingThatReturnsATask() and return await SomethingThatReturnsATask(), and you usually want to return the Task directly and not use await (for reasons described here). When used inside Task.Run, things could easily go bad if the .NET team didn't have your back.
It is important to note that asynchronous methods start running on the same thread just like any other method. The magic happens at the first await that acts on an incomplete Task. At that point, await returns its own incomplete Task. That's important - it returns, with a promise to do the rest later.
This could have meant that the Task returned from Task.Run would complete whenever Process() returns a Task. And since Process() returns a Task at the first await, that would happen when it has not yet totally completed.
The .NET team has your back
That is not the case however, because Task.Run has a specific overload for when you give it a method returning a Task. And if you look at the code, it returns a Task *that is tied to the Task you return.
That means that the Task returned from Task.Run(() => Process()) will not complete until the Task returned from Process() has completed.
So your code is fine the way it is.

Lack of await warning in async method that has await in a lambda

Either Visual Studio is confused, or I am (probably me).
If I have
public async Task<Response> DoSomething()
{
//stuff
listOfStuff.ForEach(async s => await _repo.DoThing(s));
return new Response(listOfStuff.Count);
}
It complains that
This async method lacks 'await' ...
However if I change my method to
public async Task<Response> DoSomething()
{
//stuff
foreach (var s in listOfStuff)
{
await _repo.DoThing(s);
}
return new Response(listOfStuff.Count);
}
Then it is perfectly happy and the warning goes away.
So twofold question, is the warning correct and if it is, what is the reasoning for the difference? I'm under the impression that the two methods are intrinsically the same, if the warning is correct, then I must assume that my impression is wrong.
In the first version, the DoSomething function lacks an await operator. The only await is within the async void lambda passed to the ForEach method. In the second version the DoSomething function has an await as part of the actual body of the function and thus you get no warning. It doesn't matter if the listOfStuff may or may not be empty, the condition that the method needs an await is satisfied.
Now the functional difference may not be immediatly clear but it is critical. As stated the first version uses an async void method. That is un-awaitable and the method will therefore continue before the async operation completes as you can see with this test:
[Test]
public void DoSomething()
{
var sw = Stopwatch.StartNew();
var list = Enumerable.Range(0, 10).ToList();
list.ForEach(async x => await Task.Delay(TimeSpan.FromSeconds(1)));
Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
}
Result 6ms, not the 10 seconds we'd expect. The second version of your code is a properly awaitable async Task:
[Test]
public async Task DoSomething()
{
var sw = Stopwatch.StartNew();
var list = Enumerable.Range(0, 10).ToList();
foreach(var x in list)
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
Console.WriteLine($"{sw.ElapsedMilliseconds}ms");
}
And we see the result is: 10032ms right within expectations.
If we replace the lambda with a local function, things may become clearer:
public async Task<Response> DoSomething()
{
//stuff
listOfStuff.ForEach(ProcessStuffAsync);
return new Response(listOfStuff.Count);
async Task ProcessStuffAsync(Stuff s) // local function
{
await _repo.DoThing(s);
}
}
The DoSomething method returns a Task, but it is not really asynchronous because it lacks an await. So the Task returned will be in a completed state. All code inside DoSomething (excluding the code inside the local function) will run synchronously.
The local function ProcessStuffAsync is trully asynchronous, and will return one Task each time is called. These tasks are neither awaited nor stored somewhere inside the DoSomething method, so they are fire-and-forget tasks. Nobody knows what's gonna happen to them.
Update: The code above doesn't compile because List.ForEach cannot accept the ProcessStuffAsync local function as argument. The compiler complains that it has wrong return type. To make the code compile, the local function must return void. But async void functions are a can of worms by themselves.

Multiple hierarchy of task

I want to call a task which itself call a async method which inturn returna bool value.
I want to do something on the basis of that outcome.
I can get the data on outcome.Result.Result but this does not look good and I wish to have the output in outcome.Result.
I can not figure it out.
Can someone please guide.
private void OnValidated(ValidatedIntergrationEvent evt)
{
var outcome=Task.Factory.StartNew(() => mydata.UpdateValidated());
if (outcome.Result.Result)//This work fine but I think I need something to do so that outcome.Result gives my solution.
{ }
else { }
}
public async Task<bool> UpdateValidated()
{
var result= await Mediator.Send(new ValidatedEvent(this));
return result;
}
public async Task<bool> Handle(ValidatedEvent notification, CancellationToken cancellationToken)
{ //dO WORK
// return Task.FromResult(true);
return true;
}
Since UpdateValidated is already asynchronous, you should just call it directly to execute it. Things like Task.Factory.StartNew or Task.Run offer a way to put synchronous tasks on a new thread so that they can run asynchronously. So you should just call it directly:
private void OnValidated(ValidatedIntergrationEvent evt)
{
var outcome = mydata.UpdateValidated()
// Note: this WILL block, regardless of how you call the async function
var result = outcome.Result;
}
You should try to avoid using .Result though, as this will block synchronous functions until the asynchronous result is ready, and may even cause deadlocks. If the OnValidated is a standard event handler, you could make it asynchronous instead and await your task:
private async void OnValidated(ValidatedIntergrationEvent evt)
{
var result = await mydata.UpdateValidated()
}
But this make this event handler fire and forget which can be dangerous. So you should really try to change your code that you are truly running asynchronously when calling asynchronous code.
Finally, note that you can force the asynchronous task onto a separate thread using Task.Run. This is useful when the asynchronous call also does a lot on the CPU:
var outcome = Task.Run(() => mydata.UpdateValidated());
This looks very similar to your Task.Factory.StartNew() call but returns only a Task<bool> instead of your Task<Task<bool>>. This is because Task.Run has an overload that explicitly allows you to call asynchronous methods which makes Task.Run just pass on the result.

Passing a task as parameter

I am not sure whether this is possible, so here me out:
I have a sequence of action to perform multiple
async Task MethodA(...)
{
// some code
// a call to specific Async IO bound method
// some code
}
there are also MethodB(), MethodC(), etc, and all of the have exactly the same code, except for the call to specific Async IO bound method. I am trying to find a way to pass a task pointer to a method, so that we can execute it later in a Method().
What i am currently doing is this:
private async Task Method(Func<Task<Entity>> func)
{
// some code
var a = await task.Run(func);
// some code
}
var task = async () => await CallToIOBoundTask(params);
Method(task);
This code, however, pulls a new thread each time, which is not required for IO bound task, and should be avoided.
So, is there a way to refactor the code so that no ThreadPool thread is used? A goal is to have a code like this:
private async Task Method(Task<Entity> task)
{
// some code
var a = await task;
// some code
}
It is also important to mention that different IO calls have different method signatures. Also, a task can start to execute only in Method() body, and not before.
Of course, simply invoke the func, get back a task, and await it:
async Task Method(Func<Task<Entity>> func)
{
// some code
var a = await func();
// some code
}
Also, when you're sending that lambda expression, since all it's doing is calling an async method which in itself returns a task, it doesn't need to be async in itself:
Method(() => CallToIOBoundTask(params));
That's fine as long as all these calls return Task<Entity>. If not, you can only use Task (which means starting the operation and awaiting its completion) and you won't be able to use the result.

await AsyncMethod() versus await await Task.Factory.StartNew<TResult>(AsyncMethod)

Given the following method:
public async Task<MyObject> DoSomethingAsync() {
// do some work
await OpenSomeFileAsync();
return new MyObject();
}
Is there a difference between:
public async void SomeEventHandler(EventArgs args) {
var myObject = await await Task.Factory.StartNew<Task<MyObject>>( DoSomethingAsync);
// do something with myObject
}
and:
public async void SomeEventHandler(EventArgs args) {
var myObject = await DoSomethingAsync();
// do something with myObject
}
I was thinking that the "do some work" part of DoSomethingAsync would happen immediately in a new task in the first case, but to be honest I don't really understand fully how Tasks, async and await are working, and I'm pretty sure I'm just overcomplicating things for myself.
EDIT:
This question came about from looking at this Metro example:
http://code.msdn.microsoft.com/windowsapps/Sharing-Content-Target-App-e2689782
Specifically in MainPage.xaml.cs, they have this:
var unused = Task.Factory.StartNew(async () => { // some work... });
// unused is of type Task<TResult>
I was trying to rework it without using an anonymous async function and I started wondering, why not just write an async method and await it, instead of calling StartNew and handing in an async function?
Most of the time, adding another Task is not useful, but in some cases, it can be.
The difference is if you're on the UI thread (or something similar) and execute DoSomethingAsync() directly, its first part (// do some work) will also execute on the UI thread, and so will any continuation parts of the method (unless they use ConfigureAwait()). On the other hand, if you start another Task, both the first part and any following parts of DoSomethingAsync() will execute on the ThreadPool.
If DoSomethingAsync() is written correctly, adding another Task shouldn't give you any advantages (and will give you the disadvantage of more overhead), but I can imagine there are cases where it will make a difference.
Also, instead of using Task.Factory.StartNew() and two awaits, you could write:
await Task.Run(DoSomethingAsync);
Yes, there is a difference: in the first form, you have an extra level of Task, which brings absolutely nothing useful.
The first form is basically equivalent to this:
Task<Task<MyObject>> task1 = Task.Factory.StartNew<Task<MyObject>>( DoSomethingAsync);
Task<MyObject>> task2 = await task1;
var myObject = await task2;
So it doesn't really make sense: you're creating a task that just... creates another task.

Categories