Await Task.WhenAll() inside task not awaiting - c#

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.

Related

WhenAll Task.Run Tasks Hang when Exceptions Occur

I have a minimal example of some async code that is exhibiting strange behavior. This is sandbox code, more geared at trying to understand async better --
private async Task ExhibitStrangeBehaviorAsync()
{
async Task TaskA()
{
await Task.Run(async () =>
{
throw new Exception(nameof(TaskA));
await Task.Yield();
});
}
async Task TaskB()
{
await Task.Run(() =>
{
throw new Exception(nameof(TaskB));
});
}
var tasks = new List<Task>
{
TaskA(),
TaskB(),
};
var tasksTask = Task.WhenAll(tasks);
try
{
await tasksTask;
}
catch
{
Debug.WriteLine(tasksTask.Exception.Message);
}
}
Intermittently, this code will hang. I would like to better understand why. My guess currently is the intermittent nature is due to the out-of-order execution of the aggregated tasks, and/or this line from Asynchronous Programming:
Lambda expressions in LINQ use deferred execution, meaning code could end up executing at a time when you're not expecting it to.
TaskA would fall in this category.
The code does not seem to hang if TaskB also Task.Runs an async lambda, or if neither local Task function contains Task.Run, e.g.
async Task TaskA()
{
//await Task.Run(async () =>
//{
throw new Exception(nameof(TaskA));
await Task.Yield();
//});
}
async Task TaskB()
{
//await Task.Run(() =>
//{
throw new Exception(nameof(TaskB));
//});
}
Can anybody shed some light on what's going on here?
EDIT
This is executing in the context of a UI thread, specifically that of a Xamarin.Forms application.
EDIT 2
Here is another variant on it that runs straight out of the Xamarin.Forms OnAppearing lifecycle method. I had to modify TaskA/B slightly, though they break this way with the original setup above as well.
protected async override void OnAppearing()
{
base.OnAppearing();
async Task TaskA()
{
await Task.Run(async () =>
{
throw new InvalidOperationException();
await Task.Delay(1).ConfigureAwait(false);
}).ConfigureAwait(false);
}
async Task TaskB()
{
await Task.Run(() => throw new ArgumentException()).ConfigureAwait(false);
}
var tasks = new List<Task>
{
TaskA(),
TaskB(),
};
var tasksTask = Task.WhenAll(tasks);
try
{
await tasksTask;
}
catch
{
Debug.WriteLine(tasksTask.Exception.Message);
}
}
There is some chance this may be related to another issue I have had - I am using an older version of Xamarin.Forms, one which has problems with its OnAppearing handling async correctly. I am going to try with a newer version to see if it resolves the issue.
I'm going to guess you're calling ExhibitStrangeBehaviorAsync().Wait() in a GUI app (or similar), as that's the only situation which I think of which can cause a deadlock here. This answer is written on that assumption.
The deadlock is this one, cause by the fact that you're running an await on a thread which has a SynchronizationContext installed on it, and then blocking that same thread higher up the callstack with a call to .Wait().
When you run TaskA() and TaskB(), both of those methods post some work to the ThreadPool, which takes a variable amount of time. When the ThreadPool gets around to actually executing the throw statements, this causes the Task returned from TaskA / TaskB to complete with an exception.
tasksTask will complete when the two tasks returned from TaskA and TaskB complete.
The race comes from the fact that, at the point that this line is executed:
await tasksTask;
the task tasksTask may or may not have completed. tasksTask will have completed if the Tasks returned from TaskA and TaskB have completed, so it's a race against the main thread's progression towards the await tasksTask line, against how fast the ThreadPool can run both of those throw statements.
If tasksTask is completed, the await happens synchronously (it's smart enough to check whether the Task being awaited has already completed), and there's no chance of a deadlock. If tasksTask hasn't completed, then my guess is that you're hitting the deadlock described here.
This is also consistent with your observation that removing the calls to Task.Run removes the deadlock. In this case, the tasks returned from TaskA and TaskB complete synchronously as well, so there's no race.
The morale of the story is, as is oft-repeated, do not mix async and sync code. Do not call .Wait() or .Result on a Task which is influenced in any way by await. Also consider tactical use of .ConfigureAwait(false) to guard against other people calling .Wait() on tasks which you produce.

Can somebody explain this deadlock behaviour

TLDR: In my example (ASP.NET) below why does task1.Result and task2.Result result in a deadlock and task3.Result does not?
We have a class in our code, where I cannot easily mark the method as async and keep the code from blocking while waiting for an async task to finish. The reason is that our framework does not support that. Therefore I tried to find a solution with task.Result and got some deadlocks. Luckily I found a solution (see task3). Now I tried to find out, what is the difference between task1, task2 and task3 to understand why the first two result in a deadlock and the third does not.
Using the debugger I did not see any difference like task3 being run before task3.Result is called. It is still in WaitingForActivation state like the other two. Can anyone explain to me, how task3 can work?
public class HomeController : Controller
{
public ActionResult GetSomething()
{
var task1 = GetSomethingAsync();
var task2 = Task.Run(async () => await task1);
var task3 = Task.Run(async () => await GetSomethingAsync());
return Content(task1.Result);
// return Content(task2.Result);
// return Content(task3.Result);
}
private static async Task<string> GetSomethingAsync()
{
return await Task.Run(() => "something");
}
}
The root of the problem is the await here:
private static async Task<string> GetSomethingAsync()
{
return await Task.Run(() => "something");
}
The context is captured before entering the awaiting, and the context is the main thread. So after the awaiting the context must be restored, so the continuation is scheduled to run in the main thread. Since the main thread is blocked at this point, it can't process the continuation, hence the deadlock.
To prevent the capturing of the context you could configure this await with ConfigureAwait(false).
Update: By continuation I mean the code inside GetSomethingAsync that follows after the awaiting. Although there is no code after that, it seems that the compiler does bother to create an actual continuation for this no-op part of the method (otherwise a deadlock should not occur in your example).
It should be noted that the compiler transforms an async method to a Task that consists of multiple mini-tasks. Every await encountered in the path of the execution causes the creation of a mini-task that is the continuation of the awaited task. All these mini-tasks are completed one after the other, and the completion of the last one signals the completion of the "master-task" that is returned by the async method.
What ever GetSomethingAsync() does it is done by the calling thread until some operation (OP) can not be completed right away (for example io) then the controlflow is given to the calling function but.
If you then access the Result property on the returned Task object the thread will be blocked.
This leads to the problem that even is the OP is finished the thread will not know about it because he is busy waiting for the completion of the Task
If however you let GetSomethingAsync() be exectuted by some thread-pool thread (which Task.Run(...) does) the thread-pool thread can finish the OP and the calling thread can be notified that the Task has completed.
Update:
Your second approch does not work because the task was still started on your main thread. If you have this methode
public static async Task DoStuffAsync()
{
Console.WriteLine($"Doing some stuff1 on thread {Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(50);
Console.WriteLine($"Doing some stuff2 on thread {Thread.CurrentThread.ManagedThreadId}");
}
and run this code in an appilcation with an SynchronizationContext
var task = DoStuffAsync();
Console.WriteLine($"Doing main stuff on thread {Thread.CurrentThread.ManagedThreadId}");
await Task.Run(async () => await task);
It will output something like:
Doing some stuff1 on thread 1
Doing main stuff on thread 1
Doing some stuff2 on thread 1
So with the code line Task.Run(async () => await task) you only achieved that a thread-pool thread waits on the completion of your original Task, but this in turn creates a new Task that if not handeld by awaiting it causes a deadlock.

`await Task.Run(() => DoWork1Async())` instead of `await DoWork1Async()`?

There are following methods,
async Task DoWork1Async() { .... };
async Task DoWork2Async() { .... };
async Task DoWork3Async() { .... };
I read the following code
await Task.Run(() => DoWork1Async());
await Task.Run(() => DoWork2Async());
await Task.Run(() => DoWork3Async());
instead of
await DoWork1Async();
await DoWork2Async();
await DoWork3Async();
What's the difference between these two?
When you run (within a method marked async)
await DoWork1Async();
your code calls DoWork1Async within a state machine the compiler sets up. At that point, you code relinquishes control back to that state machine. When the task completes, the rest of the code in your method continues.
Remember that async code doesn't necessarily run on a separate thread (for example, if you are doing asynchronous I/O).
When you run:
await Task.Run(() => DoWork1Async());
your DoWork1Async is dispatched as work to the Thread Pool. It is executed on a different thread (a thread pool thread). When that work is completed, that same state machine mechanism hands control back to you code to continue running.
In the second case, your code always runs on a thread pool thread. In the first case, you may not be using an extra thread at all (depending on how DoWork1Async is coded)
await Task.Run(() => DoWork1Async());
Starts a Task, which will call DoWork1Async. This is guaranteed to be asynchronous no matter how DoWork1Async is implemented.
Note: Task.Run(Action<Task<T>>) returns a Task<T>,
not a Task<Task<T>>. When your lambda returns a Task, Task.Run() returns a Task that completes with the result of the inner task. Thus you do not need to do awkward things like await await Task.Run(() => return a Task).
await DoWork1Async();
Calls DoWork1Async synchronously on the current thread. If DoWork1Async executes an await statement, then work will be suspended and the remainder of the work will occur asynchronously. However, if DoWork1Async completes execution without hitting an await, then control will return to your caller and will then start DoWork2Async all synchronously.
So in short, the first form guarantees the DoWork1Async won't start or finish synchronously.
The second form will start DoWork1Async synchronously, and may even finish it synchronously depending upon how it is written.
--
Here's a fiddle showing the difference:
https://dotnetfiddle.net/GhrO8x
Notice how in the first case DoWork() starts and executes completely synchronously before we even await its Task while in the 2nd case it executes asynchronously after we await its task.

Run I\O bunch threads in asynchronous manner [duplicate]

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));
}
}

Async/Await execution steps

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.

Categories