async await on anonamous methods - c#

This works
Task <string> t = Task <string> .Factory.StartNew(() => {
return "test";
});
but if I change this to the below gives complilation error why?
Task <string> t = Task <string> .Factory.StartNew(asyc() => {
await Thread.sleep(10000);
return "test";
});

The reason for your issue is that the async method does not return a string but a Task<string>. So the correct return value for your function would be a Task<Task<string>>. Be aware that the outer task will be marked as completed as soon as the inner task is created and from that point forward you would have to wait for the inner task.
I suggest you are not using Task.Factory.StartNew but rather Task.Run since this function has a overload that properly handles async inner functions and unwraps the tasks. Using Task.Run is a good general idea, since you rarely need the Task created the way that Task.Factory.StartNew does.
So I suggest you change the code to:
Task<string> t = Task.Run(async () =>
{
await Task.Delay(10000);
return "test";
});
But if you are sure that you want to use Task.Factory.StartNew you can use this:
Task<Task<string>> t = Task.Factory.StartNew(async () =>
{
await Task.Delay(10000);
return "test";
});
EDIT: Just spotted that you are wrongly using Thread.Sleep. You need something that returns a Task to await it (or rather a awaitable object).
The function that does that for a delay is Task.Delay. This gives you a Task that can be awaited that completes after a set time.

Related

Are the await / async keywords needed under Task.Run?

I have an async lambda expression wrapped under Task.Run.
However, it looks like I can drop the async and await keywords and they will produce the same result.
t1 = Task.Run(() => DoSomethingExpensiveAsync());
t2 = Task.Run(() => DoSomethingExpensiveAsync());
await Task.WhenAll(t1, t2);
vs
var t1 = Task.Run(async () => await DoSomethingExpensiveAsync());
var t2 = Task.Run(async () => await DoSomethingExpensiveAsync());
await Task.WhenAll(t1, t2);
How come the compiler let me do this and what is happening behind
the scene?
Is there a situation where adding them will make a
difference?
There are actually three variants.
var task = Task.Run(() => DoSomethingExpensiveAsync());
^ This one declares a new anonymous non-async function that calls DoSomethingExpensiveAsync() and returns its Task. The compiler compiles this anonymous function and passes it as an argument to Task.Run().
var task = Task.Run( async () => await DoSomethingExpensiveAsync() );
^ This one declares a new anonymous async function that calls DoSomethingExpensiveAsync(). It then returns an incomplete Task, waits for DoSomethingExpensiveAsync() to finish, and then signals the task as complete.
var task = Task.Run(DoSomethingExpensiveAsync);
^ This one does not declare a new anonymous function at all. A direct reference to DoSomethingExpensiveAsync will be passed as an argument to Task.Run().
All of these are valid because all three versions return a Task and therefore match the overload of Task.Run() that accepts a Func<Task>.
As a black box, all three calls will end up doing the same thing. However the first two result in a new function being compiled (although I'm not certain it wouldn't be optimized away) and the second one also results in another state machine being created for it.
The difference might be clearer if we rewrite them without using lambda expressions or anonymous functions. The following code does exactly the same thing:
//This is the same as Task.Run( () => DoSomethingExpensiveAsync());
Task Foo()
{
return DoSomethingExpensiveAsync();
}
var task = Task.Run(Foo);
//This is the same as Task.Run(async () => await DoSomethingExpensiveAsync());
async Task Bar()
{
return await DoSomethingExpensiveAsync();
}
var task = Task.Run(Bar);
The difference between these two is that one "elides" tasks while the other doesn't. Stephen Cleary has written a whole blog on the subject.
How come the compiler let me do this and what is happening behind the scene?
The overload of Task.Run that you're invoking takes a Func<Task> - that is, a Task-returning function. It doesn't matter where the Task comes from; the function just needs to return it from somewhere.
If you pass a delegate without async and await, then the delegate is just calling a Task-returning function and returns that same Task. If you pass a delegate with async and await, then the delegate calls the Task-returning function and awaits it; the actual Task returned from the delegate is created by the async keyword.
In this case, the two are semantically equivalent. Using the async/await keywords are a bit less efficient, since the compiler creates a state machine for the async delegate.
Is there a situation where adding them will make a difference?
Yes. In the general case, you should keep async and await. Only remove them in extremely simple "passthrough" situations like the one here.
Your code is the same as
t1 = DoSomethingExpensiveAsync();
t2 = DoSomethingExpensiveAsync();
await Task.WhenAll( t1, t2 );
because Task.Run( Func< function ) will return a proxy of the task generated by function. There is no other Task created, and so you are awaiting the original tasks.
When you already have an async method then there is no need to use Task.Run at all.
Without knowing what DoSomethingExpensiveAsync it's impossible to tell for certain what will happen.
Let's assume DoSomethingExpensiveAsync is something like this:
async Task DoSomethingExpensiveAsync()
{
SynchronousMethod();
await AsynchronousMethod();
}
In the first snippet, Task.Run will schedule the invocation of DoSomethingExpensiveAsync to the thread pool and returns as soon as SynchronousMethod returns.
In the second snippet, Task.Run will schedule the invocation of DoSomethingExpensiveAsync to the thread pool and returns when the Task return by DoSomethingExpensiveAsync is completed.

Is async and unwrap necessary for StartNew()?

I have this code:
var task = Task.Factory.StartNew(() => service.StartAsync(ct), ct);
but I'm wondering if it should instead be this:
var task = Task.Factory.StartNew(async () => await service.StartAsync(ct), ct).Unwrap();
Is the first one correct to start my async service? Or is the second one better?
Consider the type of task returned, the first one yields Task<Task<int>> while the second yields Task<int>. So really the first one is a Task representing starting of the inner task, while the second, unwrapped, represents the Task returned by the inner method representing the service starting. Finally you can also Unwrap the first and get the same effect without the async/await which is unnecessary here. None of this really covers what the need for StartNew is at all in this case just reviews the return types your looking at.
Consider the following code:
public class AsyncTesting
{
public void StartServiceTest()
{
Task<Task<int>> tsk1 = Task.Factory.StartNew(() => StartAsync());
Task<int> tsk2 = Task.Factory.StartNew(() => StartAsync()).Unwrap();
Task<int> tsk3 = Task.Factory.StartNew(async () => await StartAsync()).Unwrap();
}
public Task<int> StartAsync() => Task.Delay(2500).ContinueWith(tsk => 1);
}
The method that does not Unwrap returns a Task that represents starting the internal Task not the work it does.
As JSteward explain in their answer, the first line of code is wrong. It doesn't do what you expect it to do:
Task<Task> task = Task.Factory.StartNew(() => service.StartAsync(ct), ct); // Buggy
The second line has the correct behavior, but not because of the async/await. The async/await can be safely elided. What makes it correct is the Unwrap. It is still problematic though, because it violates the guideline CA2008 about not creating tasks without passing a TaskScheduler.
The best way to solve your problem is to use the Task.Run method:
Task task = Task.Run(() => service.StartAsync(ct), ct); // Correct
You can read about the differences between Task.Run and Task.Factory.StartNew in this article by Stephen Toub.

Why await an async function directly not work without assigning it to a Task variable

Typically, I do the following
public static async Task dosth()
{
List<Task> job = new List<Task>();
for (int i = 0; i < 3; i++)
{
job.Add(sleep());
}
Task.WhenAll(job.ToArray());
}
static async Task sleep()
{
await Task.Delay(1000);
Console.WriteLine("Finish new");
}
It works smoothly, no problem. But when I do a review on my own code (trying using other syntax to do the same job), I suddenly figure out the following two are different.
public static async Task dosthA()
{
//This will be working synchronously, take 3 seconds.
await sleep();
await sleep();
await sleep();
//This will be working asynchronously, take 1 second only.
Task A = sleep();
Task B = sleep();
Task C = sleep();
await A;
await B;
await C;
}
Why assigning the async function to a new variable make difference? I originally think they are the same.
Update
Why it is confusing me is, actually in Microsoft doc on Async-await,
They stated the following in their code.
// Calls to TaskOfTResult_MethodAsync
Task<int> returnedTaskTResult = TaskOfTResult_MethodAsync();
int intResult = await returnedTaskTResult;
// or, in a single statement
int intResult = await TaskOfTResult_MethodAsync();
They are actually different, why they use //or , in a single statement, just because it makes no different in their own example?
This is because when you are returning a running Task when you call Sleep() even when you're assigning to a variable.
The confusion is that the Task does not begin if you assign it to a variable (A, B, or C) until you call await A; but that's not true. As soon as you assign sleep(); to A, sleep() was called; therefore the Task in the sleep() method is running. Assigning it to a variable or not the Task begins when you call the method; because in the method you start the Task.
Knowing this; when you call:
await A;
await B;
await C;
A, B, and C, have already starting simultaneously... After awaiting A it is most likely B, and C have also completed or are milliseconds from completing.
There are situations where you can reference a Task that hasn't started yet but you would have to purposely return a non-running Task to do that.
To answer the edit to your question also.
Tasks have a method called GetAwaiter() which returns a TaskAwaiter. In C# when you write var task = sleep(); then you're assigning the actual Task to the task variable. All the same when you write await sleep(); the compiler does some cool stuff and it actually calls the Task.GetAwaiter() method; which is subscribed to. The Task will run and when it is complete the TaskAwaiter fires the continuation action. This can't be explained in a simple answer but to know the outer logic helps.
Among other things the TaskAwaiter implements ICriticalNotifyCompletion which in turn implements INotifyCompletion. Both have one method each, OnCompleted(Action) and UnsafeOnCompleted(Action) (you can guess which is which by naming convention).
Another thing to note is that Task.GetAwaiter() returns a TaskAwaiter but Task<TResult>.GetAwaiter() returns a TaskAwaiter<TResult>. There's not a strong difference in the two but there is a difference in the GetResult() method of the two tasks; which is what's called while marshalling back to the proper threading context. The TaskAwaiter.GetResult() returns void and the TaskAwaiter<TResult>.GetResult() returns TResult.
I feel like if I push further into this I'll have to write pages to explain it all in detail... Hopefully just explaining your question and pulling the curtain back a little bit will shed enough light to help you both understand and dig deeper if you're more curious.
Ok, so based on the comment below I want to describe my answer a little bit further.
I'll start this simple; let's just make a Task; one that isn't running, and look at it first.
public Task GetTask()
{
var task = new Task(() => { /*some work to be done*/ });
//Now we have a reference to a non-running task.
return task;
}
We can now call code like:
public async void DoWork()
{
await GetTask();
}
… but we'll be waiting forever; until the application ends, because the Task was never started. However; we could do something like this:
public async void DoWork()
{
var task = GetTask();
task.Start();
await task;
}
… and it will await the running Task and continue once the Task is complete.
Knowing this you can make as many calls to GetTask() as you like and you'll only be referencing Tasks that have not started.
In your code it's just the opposite, which is fine, as this is the most used way. I encourage you to make sure your method names notify the user of how you're returning the Task. If the Task is already running the most common convention is the end the method name with Async. Here's another example doing it with a running Task for clarity.
public Task DoTaskAsync()
{
var task = Task.Run(() => { /*some work to be done*/ });
//Now we have a reference to a task that's already running.
return task;
}
And now we will most likely call this method like:
public async void DoWork()
{
await DoTaskAsync();
}
However; note that if we simply want to reference the Task just like we did earlier, we can, the only difference is this Task is running where the one prior was not. So this code is valid.
public async void DoWork()
{
var task = DoTaskAsync();
await task;
}
The big take away is how C# handles the async / await keywords. async tells the compiler that the method is going to become a continuation of a Task. In short; the compiler knows to look for all await calls and put the rest of the method in a continuation.
The await keyword tells the compiler to call the Task.GetAwaiter() method on the Task ( and basically subscribe to the INotifyCompletion and ICriticalNotifyCompletion) to signal the continuation in the method.
And this I wanted to add just incase you weren't aware. If you do have more than one task that you want to await but would rather await one task as if they were all one then you can do that with Task.WhenAll() So instead of:
var taskA = DoTaskAsync();
var taskB = DoTaskAsync();
var taskC = DoTaskAsync();
await taskA;
await taskB;
await taskC;
You could write it a little cleaner like so:
var taskA = DoTaskAsync();
var taskB = DoTaskAsync();
var taskC = DoTaskAsync();
await Task.WhenAll(taskA, taskB, taskC);
And there are more ways of doing this sort of thing built in; just explore it.

async within a LINQ code - Clarification?

Almost every SO's answer regarding this topic , states that :
LINQ doesn't work perfectly with async
Also :
I recommend that you not think of this as "using async within LINQ"
But in Stephen's book there is a sample for :
Problem: You have a collection of tasks to await, and you want to do some
processing on each task after it completes. However, you want to do
the processing for each one as soon as it completes, not waiting for
any of the other tasks.
One of the recommended solutions was :
static async Task<int> DelayAndReturnAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
// This method now prints "1", "2", and "3".
static async Task ProcessTasksAsync()
{
// Create a sequence of tasks.
Task<int> taskA = DelayAndReturnAsync(2);
Task<int> taskB = DelayAndReturnAsync(3);
Task<int> taskC = DelayAndReturnAsync(1);
var tasks = new[] { taskA, taskB, taskC };
var processingTasks = tasks.Select(async t =>
{
var result = await t;
Trace.WriteLine(result);
}).ToArray();
// Await all processing to complete
await Task.WhenAll(processingTasks);
}
Question #1:
I don't understand why now async inside a LINQ statement - does work . Didn't we just say "don't think about using async within LINQ" ?
Question #2:
When the control reaches the await t here — What is actually happen? Does the control leaves the ProcessTasksAsync method ? or does it leaves the anonymous method and continue the iteration ?
I don't understand why now async inside a LINQ statement - does work . Didn't we just say "don't think about using async within LINQ" ?
async mostly doesn't work with LINQ because IEnumerable<T> extensions don't always infer the delegate type properly and defer to Action<T>. They have no special understanding of the Task class. This means the actual async delegate becomes async void, which is bad. In the case of Enumerable.Select, we have an overload which returns a Func<T> (which in turn will be Func<Task> in our case), which is equivalent to async Task, hence it works fine for async use-cases.
When the control reaches the await t here — What is actually happen? Does the control leaves the ProcessTasksAsync method ?
No, it doesn't. Enumerable.Select is about projecting all elements in the sequence. This means that for each element in the collection, await t which will yield control back to the iterator, which will continue iterating all elements. That's why you later have to await Task.WhenAll, to ensure all elements have finished execution.
Question 1:
The difference is that each task is continued with additional processing which is: Trace.WriteLine(result);. In the link you pointed to, that code does not change anything, just creates overhead of awaiting and wrapping with another task.
Question 2:
When the control reaches the await t here — What is actually happen?
It awaits for the result of ProcessTasksAsync's task, then continue with Trace.WriteLine(result);. We can say that the control leaves the ProcessTasksAsync method when we have the result and the processing is still inside the anonymous method.
At the end, we have await Task.WhenAll(processingTasks); which will await for all tasks including the additional processing (Trace.WriteLine(result);) to complete before continuing but each task does not await for the others to continue executing: Trace.WriteLine(result);
It will be better this way:
static async Task<int> DelayAndReturnAsync(int val)
{
await Task.Delay(TimeSpan.FromSeconds(val));
return val;
}
static async Task AwaitAndProcessAsync(Task<int> task)
{
var result = await task;
Console.WriteLine(result);
}
// This method now prints "1", "2", and "3".
static async Task ProcessTasksAsync()
{
// Create a sequence of tasks.
Task<int> taskA = DelayAndReturnAsync(2);
Task<int> taskB = DelayAndReturnAsync(3);
Task<int> taskC = DelayAndReturnAsync(1);
var tasks = new[] { taskA, taskB, taskC };
var processingTasks = tasks.Select(AwaitAndProcessAsync).ToArray();
// Await all processing to complete
await Task.WhenAll(processingTasks);
}
Array of Task, because AwaitAndProcessAsync returns Task.

Serializing async task and async continuation

I have long running processing that I want to perform in a background task. At the end of the task, I want to signal that it has completed. So essentially I have two async tasks that I want to run in the background, one after the other.
I am doing this with continuations, but the continuation is starting prior to the initial task completing. The expected behavior is that the continuation run only after the initial task has completed.
Here is some sample code that demonstrates the problem:
// Setup task and continuation
var task = new Task(async () =>
{
DebugLog("TASK Starting");
await Task.Delay(1000); // actual work here
DebugLog("TASK Finishing");
});
task.ContinueWith(async (x) =>
{
DebugLog("CONTINUATION Starting");
await Task.Delay(100); // actual work here
DebugLog("CONTINUATION Ending");
});
task.Start();
The DebugLog function:
static void DebugLog(string s, params object[] args)
{
string tmp = string.Format(s, args);
System.Diagnostics.Debug.WriteLine("{0}: {1}", DateTime.Now.ToString("HH:mm:ss.ffff"), tmp);
}
Expected Output:
TASK Starting
TASK Finishing
CONTINUATION Starting
CONTINUATION Ending
Actual Output:
TASK Starting
CONTINUATION Starting
CONTINUATION Ending
TASK Finishing
Again, my question is why is the continuation starting prior to the completion of the initial task? How do I get the continuation to run only after the completion of the first task?
Workaround #1
I can make the above code work as expected if I make the intial task synchronous - that is if I Wait on the Task.Delay like so:
var task = new Task(() =>
{
DebugLog("TASK Starting");
Task.Delay(1000).Wait(); // Wait instead of await
DebugLog("TASK Finishing");
});
For many reasons, it is bad to use Wait like this. One reason is that it blocks the thread, and this is something I want to avoid.
Workaround #2
If I take the task creation and move it into it's own function, that seems to work as well:
// START task and setup continuation
var task = Test1();
task.ContinueWith(async (x) =>
{
DebugLog("CONTINUATION Starting");
await Task.Delay(100); // actual work here
DebugLog("CONTINUATION Ending");
});
static public async Task Test1()
{
DebugLog("TASK Starting");
await Task.Delay(1000); // actual work here
DebugLog("TASK Finishing");
}
Credit for the above approach goes to this somewhat related (but not duplicate) question: Use an async callback with Task.ContinueWith
Workaround #2 is better than Workaround #1 and is likely the approach I'll take if there is no explanation for why my initial code above does not work.
Your original code is not working because the async lambda is being translated into an async void method underneath, which has no built-in way to notify any other code that it has completed. So, what you're seeing is the difference between async void and async Task. This is one of the reasons that you should avoid async void.
That said, if it's possible to do with your code, use Task.Run instead of the Task constructor and Start; and use await rather than ContinueWith:
var task = Task.Run(async () =>
{
DebugLog("TASK Starting");
await Task.Delay(1000); // actual work here
DebugLog("TASK Finishing");
});
await task;
DebugLog("CONTINUATION Starting");
await Task.Delay(100); // actual work here
DebugLog("CONTINUATION Ending");
Task.Run and await work more naturally with async code.
You shouldn't be using the Task constructor directly to start tasks, especially when starting async tasks. If you want to offload work to be executed in the background use Task.Run instead:
var task = Task.Run(async () =>
{
DebugLog("TASK Starting");
await Task.Delay(1000); // actual work here
DebugLog("TASK Finishing");
});
About the continuation, it would be better to just append it's logic to the end of the lambda expression. But if you're adamant on using ContinueWith you need to use Unwrap to get the actual async task and store the it so you could handle exceptions:
task = task.ContinueWith(async (x) =>
{
DebugLog("CONTINUATION Starting");
await Task.Delay(100); // actual work here
DebugLog("CONTINUATION Ending");
}).Unwrap();
try
{
await task;
}
catch
{
// handle exceptions
}
Change your code to
// Setup task and continuation
var t1 = new Task(() =>
{
Console.WriteLine("TASK Starting");
Task.Delay(1000).Wait(); // actual work here
Console.WriteLine("TASK Finishing");
});
var t2 = t1.ContinueWith((x) =>
{
Console.WriteLine("C1");
Task.Delay(100).Wait(); // actual work here
Console.WriteLine("C2");
});
t1.Start();
// Exception will be swallow without the line below
await Task.WhenAll(t1, t2);

Categories

Resources