How to use Task.WaitAll to wait both tasks - c#

I have the following code which calls 2 async methods and wait for results:
private Task FirstTaskAsync() {
...
}
private Task SecondTaskAsync() {
...
}
private async void Caller() {
await FirstTaskAsync();
await SecondTaskAsync();
}
Problem is it now executes and waits for each task sequentially. I want to change it to Task.WaitAll(). Here is my change:
private async void Caller() {
var first = FirstTaskAsync();
var second = SecondTaskAsync();
Task.WaitAll(first, second);
}
But when I test it, Task.WaitAll() never returns. Can you please tell me what is missing?

First of all, you should never do async void unless you are doing a event handler (which I doubt you are), if you did async Task it makes it more obvious what your problem is.
private async Task Caller() {
await FirstTaskAsync();
await SecondTaskAsync();
}
//This still will not work...
private async Task Caller() {
var first = FirstTaskAsync();
var second = SecondTaskAsync();
Task.WaitAll(first, second);
}
Task.WaitAll returns void and you never use await in the second method, so you are executing the code synchronously and blocking on the SynchronizationContext which will cause you to get deadlocks like you are seeing.
The correct solution would be not to block but instead use Task.WhenAll which returns a Task itself which allows you to drop the async keyword and just return the result
private Task Caller() {
var first = FirstTaskAsync();
var second = SecondTaskAsync();
return Task.WhenAll(first, second);
}
However, if Caller() really is a event handler you can also do async void and just await the result.
private async void Caller() { //This should only be done if this is a event handler.
var first = FirstTaskAsync();
var second = SecondTaskAsync();
await Task.WhenAll(first, second);
}

Would this work for you?
private async void Caller()
{
Task[] tasks = new Task[2];
tasks[0] = FirstTaskAsync();
tasks[1] = SecondTaskAsync();
await Task.WhenAll(tasks);
}

Related

Await vs await Task.Delay trying to learn

If I have code that says:
public async Task Test1()
{
Task task1 = MakeEggAsync();
Task task2 = MakeBaconAsync();
await Task.WhenAll(task1, task2);
}
async Task MakeBaconAsync()
{
while (CookIsBusy)
{
//
await Task.Delay(100);
}
}
async Task MakeEggAsync()
{
await makeEgg2Async();
}
async Task makeEgg2Async()
{
while (CookIsBusy)
{
//
await Task.Delay(100);
}
}
...will the computer return to the main Test1() after it get to this line?
async Task MakeEggAsync()
{
await makeEgg2Async();
}
...or will it return only after it get to a delay? I know with threading it only returns after you get to a wait.
Sorry I am new to this and I am trying to learn.
Does the computer returns after it gets to an await or after it get to a Task.Delay? This is what I am really asking.
Every async method begins executing synchronously.
Also, objects are awaited, not methods. In other words, this code:
async Task MakeEggAsync()
{
await makeEgg2Async();
}
is roughly the same as this code:
async Task MakeEggAsync()
{
var task = makeEgg2Async();
await task;
}
So the computer returns to Test1 after the Task.Delay is invoked.

Task.Delay unexpected behavior

I have this metod:
public async Task StartAsync(Task process)
{
if (process is null)
{
throw new ArgumentNullException(nameof(process));
}
var loading = ...;
await Task.WhenAll(process, loading).ContinueWith(t => EndProgress());
}
and is called via a command like so:
private async Task TestAsync()
{
await StartAsync(new Task(async () =>
{
//just for testing purpose
await Task.Delay(15000);
}));
}
ExecuteDelegate = async param => await TestAsync();
where ExecuteDelegate is an Action<T> delegate used by command.
Why does the await Task.WhenAll line not waiting those 15 seconds from Task.Dalay?
You need to await the call to StartAsync:
private async Task TestAsync()
{
await StartAsync(new Task(async () =>
{
await Task.Delay(15000);
}));
}
NOTE: You can also simplify your code by not creating the redundant Task:
private async Task TestAsync()
{
await StartAsync(Task.Delay(15000));
}
Or even simpler:
private Task TestAsync()
{
return StartAsync(Task.Delay(15000));
}
You shouldn't use the constructor to create a Task but the static Task.Run method:
private async Task TestAsync()
{
await StartAsync(Task.Run(async () =>
{
//just for testing purpose
await Task.Delay(15000);
}));
}
The task returned by Task.Run can be awaited as expected.

Chaining async methods

I'm attempting to chain together a few async methods I've created and I believe there is some fundamental misunderstanding on my part about how this works
Here's a representation of my code:
public async Task<bool> LoadFoo()
{
return await Foo.ReadAsync("bar").ContinueWith((bar) =>
{
Foo.ReadAsync("baz").ContinueWith((baz) =>
{
Foo.ReadAsync("qux").ContinueWith((qux) =>
{
return true;
});
return true;
});
return true;
});
}
public void LoadEverything()
{
LoadFoo().ContinueWith((blah) =>
{
OtherLoadMethod();
});
}
Now I was expecting when LoadEverything() was called that all of the ReadAsync methods in LoadFoo ("bar", "baz" and "qux") would run and complete, and after they all completed then the .ContinueWith in LoadEverything would run so that OtherLoadMethod() wouldn't execute until the "bar", "baz" and "qux" ReadAsync methods finished.
What I am actually seeing is that LoadFoo gets called and then OtherLoadMethod starts to run before getting to the final completion in LoadFoo (the ContinueWith of the "qux" ReadAsync).
Can someone help clear up my misunderstanding here? Why wouldn't the execution of OtherLoadMethod wait until ReadAsync("qux") finishes and returns true?
Why wouldn't execution of OtherLoadMethod wait until ReadAsync("qux") finishes and returns true?
Because that's how await works. The continuations you register are just that: continuations. They are not executed synchronously in the current method. You are telling the framework that when the current task completes, the continuation should be executed. The Task object returned by ContinueWith() allows you to observe the completion if and when it happens. There would be no need to even return a Task object, if the ContinueWith() method blocked until the continuation was executed.
Likewise, the Task<bool> returned by your LoadFoo() method represents the overall completion of the method, including the await...ContinueWith() that you're returning. The method returns prior to completion of the continuation, and callers are expected to use the returned task if they need to wait for the continuation to complete.
All that said, I don't understand why you're using ContinueWith() in the first place. You obviously have access to await, which is the modern, idiomatic way to handle continuations. IMHO, your code should look something like this (it's not clear why you're returning Task<bool> instead of Task, since the return value is only ever true, but I assume you can figure that part out yourself):
public async Task<bool> LoadFoo()
{
await Foo.ReadAsync("bar");
await Foo.ReadAsync("baz");
await Foo.ReadAsync("qux");
return true;
}
public async Task LoadEverything()
{
await LoadFoo();
await OtherLoadMethod();
}
You can also use Unwrap:
public async Task<bool> LoadFoo()
{
await Foo.ReadAsync("bar")
.ContinueWith(_ => Foo.ReadAsync("baz")).Unwrap()
.ContinueWith(_ => Foo.ReadAsync("qux")).Unwrap();
return true;
}
public async Task LoadEverything()
{
await LoadFoo().ContinueWith(_ => OtherLoadMethod()).Unwrap();
}
Did not expect the top solution in search engine was fixing a misunderstanding but not actually the solution of the topic itself.
Chaining call can make great context focus when developing, async is good, and it is better if you know what u r doing.
Code:
//thanks for TheodorZoulias's review and input
public static class TaskHelper
{
public static async Task<TOutput> ThenAsync<TInput, TOutput>(
this Task<TInput> inputTask,
Func<TInput, Task<TOutput>> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = await continuationFunction(input).ConfigureAwait(continueOnCapturedContext);
return output;
}
public static async Task<TOutput> ThenAsync<TInput, TOutput>(
this Task<TInput> inputTask,
Func<TInput, TOutput> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = continuationFunction(input);
return output;
}
public static async Task<TInput> ThenAsync<TInput>(
this Task<TInput> inputTask,
Action<TInput> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
continuationFunction(input);
return input;
}
public static async Task<TInput> ThenAsync<TInput>(
this Task<TInput> inputTask,
Func<TInput, Task> continuationFunction,
bool continueOnCapturedContext= true)
{
var input = await inputTask.ConfigureAwait(continueOnCapturedContext);
await continuationFunction(input).ConfigureAwait(continueOnCapturedContext);
return input;
}
public static async Task<TOutput> ThenAsync<TOutput>(
this Task inputTask,
Func<Task<TOutput>> continuationFunction,
bool continueOnCapturedContext= true)
{
await inputTask.ConfigureAwait(continueOnCapturedContext);
var output = await continuationFunction().ConfigureAwait(continueOnCapturedContext);
return output;
}
public static async Task ThenAsync(
this Task inputTask,
Action continuationFunction,
bool continueOnCapturedContext= true)
{
await inputTask.ConfigureAwait(continueOnCapturedContext);
continuationFunction();
}
}

Using async/await with Dispatcher.BeginInvoke()

I have a method with some code that does an await operation:
public async Task DoSomething()
{
var x = await ...;
}
I need that code to run on the Dispatcher thread. Now, Dispatcher.BeginInvoke() is awaitable, but I can't mark the lambda as async in order to run the await from inside it, like this:
public async Task DoSomething()
{
App.Current.Dispatcher.BeginInvoke(async () =>
{
var x = await ...;
}
);
}
On the inner async, I get the error:
Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type.
How can I work with async from within Dispatcher.BeginInvoke()?
The other answer may have introduced an obscure bug. This code:
public async Task DoSomething()
{
App.Current.Dispatcher.Invoke(async () =>
{
var x = await ...;
});
}
uses the Dispatcher.Invoke(Action callback) override form of Dispatcher.Invoke, which accepts an async void lambda in this particular case. This may lead to quite unexpected behavior, as it usually happens with async void methods.
You are probably looking for something like this:
public async Task<int> DoSomethingWithUIAsync()
{
await Task.Delay(100);
this.Title = "Hello!";
return 42;
}
public async Task DoSomething()
{
var x = await Application.Current.Dispatcher.Invoke<Task<int>>(
DoSomethingWithUIAsync);
Debug.Print(x.ToString()); // prints 42
}
In this case, Dispatch.Invoke<Task<int>> accepts a Func<Task<int>> argument and returns the corresponding Task<int> which is awaitable. If you don't need to return anything from DoSomethingWithUIAsync, simply use Task instead of Task<int>.
Alternatively, use one of Dispatcher.InvokeAsync methods.
I think you can use below code and then depends of place use it with async and await or without to fire and forget:
public static Task FromUiThreadAsync(Action action)
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
Dispatcher disp = GetUiDispatcher();
disp.Invoke(DispatcherPriority.Background, new Action(() =>
{
try
{
action();
tcs.SetResult(true);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}));
return tcs.Task;
}
Use Dispatcher.Invoke()
public async Task DoSomething()
{
App.Current.Dispatcher.Invoke(async () =>
{
var x = await ...;
});
}
(Edit: This answer is wrong, but I'll fix it soon)
Declare this
public async Task DoSomethingInUIThreadAsync(Func<Task> p)
{
await Application.Current.Dispatcher.Invoke(p);
}
Use like this
string someVar = "XXX";
DoSomethingInUIThreadAsync(()=>{
await Task.Run(()=> {
Thread.Sleep(10000);
Button1.Text = someVar;
});
});
DoSomethingInUIThreadAsync receives a delegate that returns a Task, Application.Current.Dispatcher.Invoke accepts a Func callback that can be awaited.

Rewriting code to take advantage of C# async feature

How to transform such code:
public void Do2()
{
Console.WriteLine("Do2::Before");
Latent(() => Console.WriteLine("Do2::After"));
}
public void Latent(Action a)
{
registeredActions.Add(a);
}
public void TriggerActions()
{
foreach (Action a in registeredActions)
{
a();
}
}
To be usable like this:
public async void Do1()
{
Console.WriteLine("Do1::Before");
await Latent();
Console.WriteLine("Do1::After");
}
Note that I do not want Tasks to be executed on ThreadPool or on other threads or magically behind my back, just when I want them to, i.e. decide by myself when Task is "completed" and call whatever code is after await Latent(), most likely in the same thread as Do1 is called. Sample usage:
Console.WriteLine("Before Do");
ts.Do2();
Console.WriteLine("After Do, before triggering actions");
// ... do some other stuff and when it is the right time to "complete pending tasks"
ts.TriggerActions();
Console.WriteLine("After triggering actions");
I couldn't find any solution for this, all C# async samples talk about await client.GetStringAsync(.. or Thread.Sleep(... or Task.Delay(...
You use a TaskCompletionSource<T>:
Task Latent()
{
var tcs = new TaskCompletionSource<object>();
... // Apply some logic here to eventually call "tcs.TrySetResult".
return tcs.Task;
}
This can be used as such:
public async Task Do1()
{
Console.WriteLine("Do1::Before");
await Latent();
Console.WriteLine("Do1::After");
}

Categories

Resources