I have this method :
public static Task TaskMethod ()
{
Task.Delay(30000);
return Task.Run(() => Console.WriteLine("From Task") );
}
If I call it like this:
public static async Task Main()
{
Console.WriteLine("before calling the task");
TaskMethod();
Console.WriteLine("after calling the task");
Console.ReadLine();
}
I have this output:
before calling the task
after calling the task
From Task
But if I call this:
public static async Task Main()
{
Console.WriteLine("before calling the task");
await TaskMethod();
Console.WriteLine("after calling the task");
Console.ReadLine();
}
I have this result:
before calling the task
From Task
after calling the task
Is this behavior normal? Why I'm allowed to await the task without using async?
What I'm missing?
I will try to explain.
Case: You don't await the returning value then it will execute the line and proceed to execute the next.
Console.WriteLine("before calling the task"); // execute 1
TaskMethod(); // execute 2
Console.WriteLine("after calling the task"); // execute 3
The confusing output that you get is because your machine needs less time to execute the 3rd command than it needs to execute the 2nd (creating a task, starting it, printint to console). The 2nd call runs in parallel to the 3rd. This is also due to the fact that the Task.Delay call is not waiting because you don't await it and the same principle applies there as it applies here.
To give you a little examplary proof here is a code that introduces a slight synchronous delay between the 2nd and 3rd call:
public static async Task Main()
{
Console.WriteLine("before calling the task");
TaskMethod();
Thread.Sleep(50);
Console.WriteLine("after calling the task");
//Console.ReadLine();
}
This gives the starting of the 2nd call a little more time to be executed before the 3rd step is performed. And you get the output:
before calling the task
From Task
after calling the task
Now to the fact that the method Main runs actually synchronous on the main thread. This screenshot from LINQPad shows the message that Visual Studio would also display:
It tells you that the main method will block the main thread until it is finished. Because there is no await in it.
Whereas the TaskMethod inside the Main will run asynchronously and in parallel to the next commands which runs on the main thread! Whoever is faster gets to print it's message.
Why the Task.Delay call is useless without await ?=!
The Delay method returns a task which is started, actually quite exactly like your TaskMethod. If you don't await this delay task, it will run in parallel. Thus obliterating the entire effect of a delay. You should actually notice that your console prints all 3 lines at the same time, there is no delay between the second and third line!
Why I'm allowed to await the task without using async?
Because the necessity of async refers always to the method inside which the await call is made and not the method that is awaited! This can be seen in the fact that you cannot simply add an await to the Task.Delay call because the TaskMethod is not declared as async!
(Hopefully) last EDIT:
The await operator needs a Task whose execution it can await, and because your TaskMethod returns a Task the operator can be applied.
You can make nice things with it if you take the returning task. You can then decide when to wait for the end of it's execution!:
public static async Task Main()
{
Console.WriteLine("before calling the task");
Task taskToBeAwaitedMuchLater = TaskMethod();
Console.WriteLine("after calling the task");
await taskToBeAwaitedMuchLater;
Console.WriteLine("after awaiting the result of the task");
//Console.ReadLine();
}
Output:
before calling the task
after calling the task
From Task
after awaiting the result of the task
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 days ago.
The community is reviewing whether to reopen this question as of 2 days ago.
Improve this question
I have the following code block:
public class Program
{
public static void Main()
{
Task task = ExampleTaskAsync();
Console.WriteLine("Method invoked");
task.Wait();
Console.WriteLine("main finished");
}
static async Task ExampleTaskAsync()
{
Console.WriteLine("Started await");
await Task.FromResult(189);
Console.WriteLine("During await");
await Task.Delay(867);
Console.WriteLine("completed await");
}
}
When I run this code block, it always produces the following output:
Started await
During await
Method invoked
completed await
main finished
I was expecting the following output:
Started await
Method invoked
During await
completed await
main finished
Could you explain why the "During await" appears before the "Method invoked"?
When you execute Task task = ExampleTaskAsync(); that method starts running synchronously until it hits the first time there is a real Task to wait for. That is why you see "Started await" first.
Next issue is that await Task.FromResult(189); doesn't really wait: FromResult (and Task.CompletedTask) immediately return a completed task so the method doesn't need to wait and continues synchronously. That's why you also see "During await".
Next is a await Task.Delay(867); which immediately returns an imcomplete Task, which does cause the method to return an incomplete task. So you don't yet get to "completed await", but see "Method invoked".
When the delay finishes, the ExampleTaskAsync method continues and prints "completed await". Then the Task belonging to this method is complete and the Wait in the Main is over so you see the final "main finished".
Note that your Main method should also be async (async Task Main()), so you can await task, instead of using Wait() which may cause a deadlock.
When you do this: Task task = ExampleTaskAsync(); You're starting the task .Wait() just waits till its finished, it does not start it (its already started as you can tell).
Just initialize the task variable when you actually want to start the task.
If your are asking why is there a different between
Observed
...
During await
Method invoked
...
Expected
...
Method invoked
During await
...
then the answer is because await Task.FromResult(189); always finishes synchronously.
There is no point to suspend the execution of ExampleTaskAsync and give back the control to the caller.
If you copy-paste the code to sharplab you can see how the execution flow is changing during the application execution.
I also suggest to examine the generated async state machine's code.
I have a doubt. I have read that await keyword is used when we want to wait for a particular function to finish the operation.
public async void Work()
{
await SlowTask();
Console.WriteLine("Execution completed");
}
Now as per the definition, when Work() method is called, it will wait for SlowTask() method to complete its execution before printing "Execution completed". But I have a doubt that even if the await and async keyword are not used then also Work() method is going to wait for SlowTask() method to complete its execution before printing "Execution completed" because it will be executed line by line.
But I have a doubt that even if the await and async keyword are not used then also Work() method is going to wait for SlowTask() method to complete its execution before printing "Execution completed" because it will be executed line by line.
If you don't use await, it will wait for the SlowTask method to return - but it won't wait for it to complete. This is one of the trickiest aspects of understanding async/await: an async method returns as soon as it needs to await something that hasn't finished, but then it continues when that has completed.
So suppose SlowTask is:
async Task SlowTask()
{
Console.WriteLine("A");
await Task.Delay(5000);
Console.WriteLine("B");
await Task.Delay(5000);
Console.WriteLine("C");
}
This method will print A as soon as it's called, but will return when it hits the first await, because the delay won't have been completed. If you don't await SlowTask in your calling code, you'll then see "Execution completed" even though SlowTask hasn't really completed.
After the first delay has completed, SlowTask will resume, and B will be printed. It will return again (to whatever scheduled the continuation) due to the second delay, then continue and print C before completing. If you've actually awaited the task returned by SlowTask that's when you'll see "Execution completed" printed - which is probably what you want.
One thing that always helped see the difference when I first came to learn about was this scenario.
Public async Task StartTaskAsync()
{
Console.WriteLine("First Step");
Task awaitableTask = OtherMethodAsync();
Console.Writeline("Second step");
await awaitableTask;
Console.Writeline("4th Step");
}
Public async Task OtherMethodAsync()
{
await Task.Delay(2000);
Console.WriteLine("Step 3");
}
If you run this it will print out the steps in order. Because the await in the OtherMethodAsyncAsync passes control back to the calling method until whatever it is await has finished.
In the calling method StartTaskAsync it doesn't await immediately so it can continue to run some code until it waits on the task returned by the OtherMethodAsyncAsync.
If you were to make this synchronous. Ie remove all the asyncs and awaits and just return void rather than task. You would see that step 3 prints before Step 2
Can anyone explain to me why second Working! shows after Done ?
Stating
Doing Work
Working!
Done
Working!
Work completed
Second question why can't I just do like below to get Task result:
Task result = await LongOperation();
And last question is what would be the reason to use Task.Run on behalf with await/async for instance in my code? Where could it be used or is it not good to use it?
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Starting");
var worker = new Worker();
worker.DoWork();
Console.WriteLine("Done");
Console.ReadKey();
}
}
public class Worker
{
public async void DoWork()
{
Console.WriteLine("Doing work");
await LongOperation();
await LongOperation();
Console.WriteLine("Work completed");
}
private async Task LongOperation()
{
Console.WriteLine("Working!");
await Task.Delay(200);
}
}
This is because you have declared DoWork() asynchronous with a return type of void. This makes it a "fire and forget" method that is running asynchronously. If you have DoWork() return a Task instead of void, you can await it, and that would ensure your "Done" message would occur after DoWork() has completed execution.
Additionally, await unwraps the task result, so you cannot await it and get the value at the same time. If you wish to use the Task result directly, do not await it.
There is no specific area in the code you specified where you should be using Task.Run().
Working shows after Done! because in your static void Main you aren't waiting for worker.DoWork(); to complete, so the program executes the next line. You should change DoWork method like this:
public async Task DoWork()
{
//
}
And change the call to it like this:
worker.DoWork().GetAwaiter().GetResult();
You can't because using await your LongOperation will not return a Task. For example if you had a signature like this, when you use await you unwrap the result:
public Task<int> GiveANumberAsync()
{
return Task.FromResult(12);
}
int result = await GiveANumberAsync();
For this question I think I can't explain better than Stephen in this answer, where he says:
Use Task.Run to call CPU-bound methods.
There reason "Done!" appears sooner than you expect is because you do not have await in front of worker.DoWork(); (and DoWork needs to return a Task to be able to use await). So what happens is DoWork() returns immediately with execution deferred to another thread, and immediately goes to next line which is the console write "done".
Regarding Task result = await LongOperation();, await takes in as parameter awaitable object (i.e. Task), examines its .Result property on your behalf, extracts the result and returns it. So you either drop await to get the task instance, or you put await to wait for task completion and extracting the actual return value of the call.
There are a few reasons to use Task.Run or through task factory, one example being passing lambda function for execution (possibly with closure). I would refer to MSDN library on TPL for detailed dive.
Taking your questions one by one:
In Main, you do not await DoWork. This means that it is invoked, and then execution of the code in the Main continues, without waiting for DoWork to finish. As such, "Done" is printed to the console right away before the second "Working".
This isn't what the await keyword does. From the documentation:
The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work. [...]
The task to which the await operator is applied typically is the return value from a call to a method that implements the Task-Based Asynchronous Pattern. Examples include values of type Task or Task<TResult>.
Effectively, in order to await a method, it must have return type Task<T>, where T is the actual type of what you return in your code. Your method LongOperation doesn't actually return anything in this example.
Task.Run is used to run any method or block of code as a Task. It can be fired and forgotten (Task.Run([something];), or awaited like any other task (await Task.Run([something]);. See the documentation for it here, though I'm not sure it will be much help. User Stephen Cleary explained it well in this answer, along with some other pertinent information.
This example partly is taken from stack
public async Task MyMethod(string s1,sring s2)
{
Trace.TraceInformation("info");
//check input
if (s1 == null || s2 == null)
Trace.TraceInformation("error");
Task<int> longRunningTask = LongRunningOperation();
//indeed you can do independent to the int result work here
//and now we call await on the task
int result = await longRunningTask;
//use the result
Console.WriteLine(result);
}
public async Task<int> LongRunningOperation() // assume we return an int from this long running operation
{
await Task.Delay(1000); //1 seconds delay
return 1;
}
I want the MyMethod to be not blocking.
1.so is it correct that until Task<int> longRunningTask = LongRunningOperation();
the user is blocked?Should I runn the above part of code (the trace and input check) asynchronously too?if yes how? is there a way to do that without new async method implementation?
2.When we start:
Task<int> longRunningTask = LongRunningOperation();
starts executing LongRunningOperation
independent work is done on let's assume the Main Thread (Thread ID = 1) then await longRunningOperation is reached.
Now, if the longRunningOperation hasn't finished and is still running MyMethod() will return to its calling method, thus the main thread doesn't get blocked. When the longRunningOperation is done then a thread from the ThreadPool (can be any thread) will return to MyMethod() at its previous state and continue execution (in this case printing the result to the console).
A second case would be that the longRunningOperation has already finished its execution and the result is available. When reaching the await longRunningOperation the compiler knows that it has the result and will keep on executing code on the very same thread. (in this case printing result to console).
3.What happens if exception is thrown during async method?
4.If the synchronous implementation is provided can I use it?how?
1. You are incorrect about where the code retuns to the user.
Everything up to int result = await longRunningTask; is run on the same thread as the function that called MyMethod(, not the Task<int> longRunningTask = LongRunningOperation(); call.
If you want the synchronous portion of the function to also run in a background thread wrap the call to MyMethod in a Task.Run(
var myMethodTask = Task.Run(() => MyMethod("foo", "bar"));
you then can await or whatever you need on that returned task.
2. If longRunningTask is complete by the time you reach await longRunningTask the function will still continue to run on the same thread and never return to the caller till it reaches the end of the function. When it reaches the end of the function it returns to the caller with a Task already in the completed state.
If longRunningTask was not done it will return to the caller at the point of the await and return a Task that will change from the Running state to the Completed state when the function completes. When the await returns it uses the SynchronizationContext that was active when the task started to figure out what thread it should continue it's work on. If you where on the UI thread when you hit the await the work will continue on the UI thread, by default it will use a ThreadPool thread to continue the work if there was no SynchronizationContext set.
3. If a exception is thrown you see the exception when await longRunningTask returns (or the parent thread returns if you wrapped the function in a Task.Run()
4. You should use a separate method for the synchronous implementation. See the two Microsoft blog posts "Should I expose asynchronous wrappers for synchronous methods?" and "Should I expose synchronous wrappers for asynchronous methods?"
My problem is that when a Task has a Task.WhenAll() call (running other Tasks) the line of WhenAll() makes the consuming code continue execution, unlike what I would expect. So the following code outputs "finished" immediately when the Task.WhenAll() is hit, not after all the tasks in its argument are finished.
// Just a simple async method
public Task DoWorkAsync()
{
return Task.Factory.StartNew(
() =>
{
// Working
});
}
// This one used the previous one with Task.WhenAll()
public Task DoLoadsOfWorkAsync()
{
return Task.Factory.StartNew(
async () =>
{
// Working
// This line makes the task return immediately
await Task.WhenAll(DoWorkAsync(), DoWorkAsync());
// Working
});
}
// Consuming code
await DoLoadsOfWorkAsync();
Console.WriteLine("finished");
I'd expect the WriteLine() to be called when the last line of DoLoadsOfWorkAsync() is executed.
What am I doing wrong? Thanks in advance.
Task.WhenAll returns a new Task immediately, it does not block. The returned task will complete when all tasks passed to WhenAll have completed.
It is an asynchronous equivalent to Task.WaitAll, and this is the method to use if you want to block.
However you have another problem. Using Task.Factory.StartNew and passing an async delegate seems to lead to a type of Task<Task> where the outer task completes when the inner task starts to execute (rather than when it has completed).
Using the newer Task.Run avoids this.