C# Will code execution continue after await? - c#

After a lot of readings about await/async, I still have some misunderstanding about the subject.
Please provide a short answer (yes/no) and a long answer to my questions, so I can have better understanding.
Let's say we have the following method:
public async Task UnresultTaskMethod()
{
await AsyncMethod1();
await AsyncMethod2();
}
Questions:
When the execution of the code will reach AsyncMethod1, will it automatically move to call AsyncMethod2 while AsyncMethod1() is getting executed?
When the execution of the code will reach AsyncMethod2, will the execution of the method ends, and the execution will return to the caller, before the execution of AsyncMethod2 completely ends?
Is there such a cases where the execution of the method will end before the calls to async method fully completes (for example the method was void instead of task)?
When I will need to put Task.WaitAll(tasks); Task.WhenAll(tasks); at the end so I can make sure the execution will not continue before all the tasks have ended, this is the main factor of confusion for me, why to wait for a task in this way if you can wait for them by keyword await?
I was thinking when the execution will hit async method with await, it will put it on processing schedule, and continue to execute the code inside the function, I'm feeling that I misunderstood.

await roughly means 'wait until completed'
No
No
If you don't await, it might be the case, for example
public async Task UnresultTaskMethod()
{
Task.Delay(2000);
// We haven't awaited, so we're here right away
await AsyncMethod2();
}
Task.WaitAll and Task.WhenAll don't make sense when you await individual tasks right away. However, you can do this:
public async Task UnresultTaskMethod()
{
var task1 = AsyncMethod1();
var task2 = AsyncMethod2();
// The tasks are now doing their job
await Task.WhenAll(task1, task2);
// Here you are sure both task1 and task2 are completed
}
With Task.WaitAll it would be like this:
public async Task UnresultTaskMethod()
{
var task1 = AsyncMethod1();
var task2 = AsyncMethod2();
// This is not awaitable, you're blocking the current thread
Task.WaitAll(task1, task2);
// Here you are sure both task1 and task2 are completed
}
In this case, you don't need async Task, because you are not awaiting, i.e. it is effectively a void method.
Hopefully now it is a bit clearer

Related

Can't await task on MainWindow Loaded event [duplicate]

I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.

Different Behavior with wait than await [duplicate]

I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.

How to execute multiple async Tasks concurrently

I'm confused by this code.
According to the documentation that includes this code,
it invokes each task which allows them to execute
concurrently, and then awaits for them both to be complete.
I don't understand how the order of execution works. By declaring the task var firstTask = DoSomethingAsync(); does this cause the task to begin executing? I thought it is synchronous without an await expression.
public async Task RunConcurrentTasks()
{
var firstTask = DoSomethingAsync();
var secondTask = DoSomethingElseAsync();
await firstTask;
await secondTask;
}
Also, does this code achieve the same result?
public async Task RunConcurrentTasks()
{
var firstTask = DoSomethingAsync();
var secondTask = DoSomethingElseAsync();
await Task.WhenAll(firstTask, secondTask);
}
var firstTask = DoSomethingAsync(); does this cause the task to begin executing?
Yes. It had better! DoSomethingAsync promises in its name to do something asynchronously, so if it does not hand you back an executing task, then its name is a lie.
How then does execution advance to the next line to invoke the second task?
I don't understand the question.
I thought it is synchronous without an await expression.
Your belief is false. "Await" does not mean "make this asynchronous". Await neither creates nor destroys asynchrony; it merely manages existing asynchrony. DoSomethingAsync is already asynchronous independent of any await. Again, it says that it does something asynchronously, so that had better be what it does!
await in your example is just return. It means "return to my caller, and start running this method again at some time in the future after the awaited task is finished." It's an asynchronous wait.
Think of await as being like yield return. When you're in an iterator block and you encounter a yield return, the method returns, and then it picks up where it left off at some point in the future. await is basically the same; just the mechanisms are slightly different.
Another way to think of it is that await marks a point where the current method cannot continue to run until the awaited task is completed. Since the method cannot continue to run, it returns.
Again, await does not do anything to a call on its right hand side. It's just an operator, and it obeys all the normal rules of operators:
await Foo();
and
var blah = Foo();
await blah;
are the same thing, just like
var x = Foo() + Bar();
and
var f = Foo();
var b = Bar();
var x = f + b;
are the same thing. Await does not do something magical to its operands any more than + does something magical to its operands. It's just a special kind of return.
Also, does this code do the same thing?
Please don't ask two questions in one question. Post two questions if you have two questions.
The question is unclear. The semantics of both workflows are that the task returned by RunConcurrentTasks is signaled as being completed when both its child tasks are complete, if that's what you're asking.
By declaring the task var firstTask = DoSomethingAsync(); does this cause the task to begin executing?
Yes.
How then does execution advance to the next line to invoke the second task?
It will run DoSomethingAsync until it hits its first await that yields. At that point, DoSomethingAsync returns a task that has not yet completed, and the caller RunConcurrentTasks continues to the next line.
I thought it is synchronous without an await expression.
No, it's still asynchronous. await doesn't run anything. await will cause the consuming code to asynchronously wait ("await") for the task to complete.
You may find my async intro helpful.
Task Documentation
The Task class represents a single operation that does not return a value and that usually executes asynchronously. Task objects are one of the central components of the task-based asynchronous pattern first introduced in the .NET Framework 4. Because the work performed by a Task object typically executes asynchronously on a thread pool thread rather than synchronously on the main application thread...
Here is your code annotated, hopefully this makes more sense.
public async Task RunConcurrentTasks()
{
// starts DoSomethingAsync and returns a Task which contains the information about the running state of that operation
// the thread that called this gets that Task as a result immediatly and can continue on to the next statement while this is running
var firstTask = DoSomethingAsync();
// starts DoSomethingElseAsync and returns a Task which contains the information about the running state of that operation
// the thread that called this gets that Task as a result immediatly and can continue on to the next statement while this is running
var secondTask = DoSomethingElseAsync();
// suspend the execution of the method until the awaited task completes
// only then do we proceed to the next line (assuming no exception was thrown)
await firstTask;
// suspend the execution of the method until the awaited task completes
// only then do we proceed to the next line (assuming no exception was thrown)
await secondTask;
}
public async Task RunConcurrentTasks()
{
// starts DoSomethingAsync and returns a Task which contains the information about the running state of that operation
// the thread that called this gets that Task as a result immediatly and can continue on to the next statement while this is running
var firstTask = DoSomethingAsync();
// starts DoSomethingElseAsync and returns a Task which contains the information about the running state of that operation
// the thread that called this gets that Task as a result immediatly and can continue on to the next statement while this is running
var secondTask = DoSomethingElseAsync();
// suspend the execution of the method until the awaited DoSomethingAsync AND DoSomethingElseAsync have completed
// only then do we proceed to the next line (assuming no Exceptions was thrown)
await Task.WhenAll(firstTask, secondTask);
}
From comments
How would I do it synchronously, if I wanted to?
Await 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
Use await immediately after each call, this ensures that execution does not proceed to the next line until a result (or Exception) is returned from the execution of the Task being awaited. It does not actually make it synchronous in the technical sense of the word. So take your 1st example and reorder the lines so that you call await after starting the first operation and before you start your 2nd operation.
var firstTask = DoSomethingAsync();
await firstTask;
var secondTask = DoSomethingElseAsync();
await secondTask;
which can also be rewritten as
await DoSomethingAsync();
await DoSomethingElseAsync();
upon invoking the async method, with the parenthesys (), such as DoSomethingAsync(); will begin the execution of the async functionality. It will return a Task immediately, which contains information about the async functionality being executed, and lets the system know when it is finished as well.
To run them in order, just await each one individually instead of awaiting the WhenAll call. As such:
public async Task RunConcurrentTasks()
{
await DoSomethingAsync();
await DoSomethingElseAsync();
}
now DoSomethingElseAsync will wait on the call to DoSomethingAsync before executing.

Executing tasks in parallel

Ok, so basically I have a bunch of tasks (10) and I want to start them all at the same time and wait for them to complete. When completed I want to execute other tasks. I read a bunch of resources about this but I can't get it right for my particular case...
Here is what I currently have (code has been simplified):
public async Task RunTasks()
{
var tasks = new List<Task>
{
new Task(async () => await DoWork()),
//and so on with the other 9 similar tasks
}
Parallel.ForEach(tasks, task =>
{
task.Start();
});
Task.WhenAll(tasks).ContinueWith(done =>
{
//Run the other tasks
});
}
//This function perform some I/O operations
public async Task DoWork()
{
var results = await GetDataFromDatabaseAsync();
foreach (var result in results)
{
await ReadFromNetwork(result.Url);
}
}
So my problem is that when I'm waiting for tasks to complete with the WhenAll call, it tells me that all tasks are over even though none of them are completed. I tried adding Console.WriteLine in my foreach and when I have entered the continuation task, data keeps coming in from my previous Tasks that aren't really finished.
What am I doing wrong here?
You should almost never use the Task constructor directly. In your case that task only fires the actual task that you can't wait for.
You can simply call DoWork and get back a task, store it in a list and wait for all the tasks to complete. Meaning:
tasks.Add(DoWork());
// ...
await Task.WhenAll(tasks);
However, async methods run synchronously until the first await on an uncompleted task is reached. If you worry about that part taking too long then use Task.Run to offload it to another ThreadPool thread and then store that task in the list:
tasks.Add(Task.Run(() => DoWork()));
// ...
await Task.WhenAll(tasks);
If you want to run those task's parallel in different threads using TPL you may need something like this:
public async Task RunTasks()
{
var tasks = new List<Func<Task>>
{
DoWork,
//...
};
await Task.WhenAll(tasks.AsParallel().Select(async task => await task()));
//Run the other tasks
}
These approach parallelizing only small amount of code: the queueing of the method to the thread pool and the return of an uncompleted Task. Also for such small amount of task parallelizing can take more time than just running asynchronously. This could make sense only if your tasks do some longer (synchronous) work before their first await.
For most cases better way will be:
public async Task RunTasks()
{
await Task.WhenAll(new []
{
DoWork(),
//...
});
//Run the other tasks
}
To my opinion in your code:
You should not wrap your code in Task before passing to Parallel.ForEach.
You can just await Task.WhenAll instead of using ContinueWith.
Essentially you're mixing two incompatible async paradigms; i.e. Parallel.ForEach() and async-await.
For what you want, do one or the other. E.g. you can just use Parallel.For[Each]() and drop the async-await altogether. Parallel.For[Each]() will only return when all the parallel tasks are complete, and you can then move onto the other tasks.
The code has some other issues too:
you mark the method async but don't await in it (the await you do have is in the delegate, not the method);
you almost certainly want .ConfigureAwait(false) on your awaits, especially if you aren't trying to use the results immediately in a UI thread.
The DoWork method is an asynchronous I/O method. It means that you don't need multiple threads to execute several of them, as most of the time the method will asynchronously wait for the I/O to complete. One thread is enough to do that.
public async Task RunTasks()
{
var tasks = new List<Task>
{
DoWork(),
//and so on with the other 9 similar tasks
};
await Task.WhenAll(tasks);
//Run the other tasks
}
You should almost never use the Task constructor to create a new task. To create an asynchronous I/O task, simply call the async method. To create a task that will be executed on a thread pool thread, use Task.Run. You can read this article for a detailed explanation of Task.Run and other options of creating tasks.
Just also add a try-catch block around the Task.WhenAll
NB: An instance of System.AggregateException is thrown that acts as a wrapper around one or more exceptions that have occurred. This is important for methods that coordinate multiple tasks like Task.WaitAll() and Task.WaitAny() so the AggregateException is able to wrap all the exceptions within the running tasks that have occurred.
try
{
Task.WaitAll(tasks.ToArray());
}
catch(AggregateException ex)
{
foreach (Exception inner in ex.InnerExceptions)
{
Console.WriteLine(String.Format("Exception type {0} from {1}", inner.GetType(), inner.Source));
}
}

await vs Task.Wait - Deadlock?

I don't quite understand the difference between Task.Wait and await.
I have something similar to the following functions in a ASP.NET WebAPI service:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Where Get will deadlock.
What could cause this? Why doesn't this cause a problem when I use a blocking wait rather than await Task.Delay?
Wait and await - while similar conceptually - are actually completely different.
Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete. As a general rule, you should use "async all the way down"; that is, don't block on async code. On my blog, I go into the details of how blocking in asynchronous code causes deadlock.
await will asynchronously wait until the task completes. This means the current method is "paused" (its state is captured) and the method returns an incomplete task to its caller. Later, when the await expression completes, the remainder of the method is scheduled as a continuation.
You also mentioned a "cooperative block", by which I assume you mean a task that you're Waiting on may execute on the waiting thread. There are situations where this can happen, but it's an optimization. There are many situations where it can't happen, like if the task is for another scheduler, or if it's already started or if it's a non-code task (such as in your code example: Wait cannot execute the Delay task inline because there's no code for it).
You may find my async / await intro helpful.
Based on what I read from different sources:
An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
To wait for a single task to complete, you can call its Task.Wait method. A call to the Wait method blocks the calling thread until the single class instance has completed execution. The parameterless Wait() method is used to wait unconditionally until a task completes. The task simulates work by calling the Thread.Sleep method to sleep for two seconds.
This article is also a good read.
Some important facts were not given in other answers:
async/await is more complex at CIL level and thus costs memory and CPU time.
Any task can be canceled if the waiting time is unacceptable.
In the case of async/await we do not have a handler for such a task to cancel it or monitoring it.
Using Task is more flexible than async/await.
Any sync functionality can by wrapped by async.
public async Task<ActionResult> DoAsync(long id)
{
return await Task.Run(() => { return DoSync(id); } );
}
async/await generate many problems. We do not know if await statement will be reached without runtime and context debugging. If first await is not reached, everything is blocked. Sometimes even when await seems to be reached, still everything is blocked:
https://github.com/dotnet/runtime/issues/36063
I do not see why I must live with the code duplication for sync and async method or using hacks.
Conclusion: Creating Tasks manually and controlling them is much better. Handler to Task gives more control. We can monitor Tasks and manage them:
https://github.com/lsmolinski/MonitoredQueueBackgroundWorkItem
Sorry for my english.

Categories

Resources