This question already has answers here:
WaitAll vs WhenAll
(4 answers)
Closed 6 years ago.
I have this code:
List<ComponentesClasificaciones> misClasificaciones = new List<ComponentesClasificaciones>();
Task tskClasificaciones = Task.Run(() =>
{
misClasificaciones = VariablesGlobales.Repositorio.buscarComponentesClasificacionesTodosAsync().Result;
});
Task.WhenAll(tskClasificaciones);
List<ComponentesClasificaciones> misVClasificacionesParaEstructuras = new List<ComponentesClasificaciones>(misClasificaciones);
If I use Task.WhenAll, misClasificaciones does not have any element but when I use awit all I get all the elements that I request to the database.
When to use WhenAll and when to use WaitAll?
MSDN does a good job of explaining this. The difference is pretty unambiguous.
Task.WhenAll:
Creates a task that will complete when all of the supplied tasks have completed.
Task.WaitAll:
Waits for all of the provided Task objects to complete execution.
So, essentially, WhenAll gives you a task that isn't done until all of the tasks you give it are done (and allows program execution to continue immediately), whereas WaitAll just blocks and waits for all of the tasks you pass to finish.
WhenAll returns a task that you can ContinueWith once all the specified tasks are complete. You should be doing
Task.WhenAll(tskClasificaciones).ContinueWith(t => {
// code here
});
Basically, use WaitAll when you want to synchronously get the results, use WhenAll when you want to start a new asynchronous task to start some more processing
Related
This question already has answers here:
Running Multiple Tasks in Parallel
(2 answers)
Closed 2 years ago.
I have a foreach loop that goes through objects in a list, and calls a method:
foreach(var obj in objList)
{
Task task = Task.Factory.StartNew(() => obj.Method());
}
However, how do I make it so that I await only the last thread declared, so that all the threads run in parallel? If I do Task task = await Task.Factory.StartNew(() => obj.Method());, the loop awaits every thread, which is not what I want.
You keep track of the task that gets created, and await it after your loop is done.
Even though you say you want to await only the last thread, I'm taking artistic license to interpret your real need: you want to ensure all the Tasks are happening concurrently, and then you want to wait for them all to complete.
var tasks = objList.Select(obj => Task.Run(() => obj.Method())).ToList();
await task.WhenAll(tasks);
Waiting for only the last task would lead to problems:
Tasks run concurrently, there are no guarantees that the last task finishes last
You would not be able to catch / handle errors despite the last task
You should await all tasks at once:
var tasks = objList.Select(o => Task.Run(o => o.Method());
await Taks.WhenAll(tasks);
This question already has answers here:
How and when to use ‘async’ and ‘await’
(25 answers)
How do yield and await implement flow of control in .NET?
(5 answers)
Brief explanation of Async/Await in .Net 4.5
(3 answers)
Closed 2 years ago.
I never had a good chance to go deep into async/await , so I have just a gist of what it does.
So I tried it in WinForms app like this:
private async void button2_Click(object sender, EventArgs e)
{
// In below line I understand the Task is created and scheduled to execute, which in this
// simple case means, that it executes right away asynchronously.
var task = Task.Factory.StartNew(() =>
{
Task.Delay(5000).Wait();
return 12;
});
// Here we wait for the task to finish, so we don't see MessageBox yet.
var res = await task;
MessageBox.Show("Result is :" + res);
}
My question is, since we are waiting on await I expected to block UI thread, since we can go any further in that thread (to the line with MessageBox). So UI thread actually stops on method with event hadnler.
But, to my surprise, windows is responsive and everything works very well, but I didn't expect that. Can anybody explain me what is going on?
After reading this post, I still have a doubt, if await is asynchronous and doesn't block UI thread in my example, why the thread doesn't proceed to next line with MessageBox? How the UI thread proceeds then?
Is good idea that code after await is just another Task, like in ContinueWith? But it comes back to UI context?
Async methods are a lot like generator methods. The compiler will split up your code at each await operator. A block of code is inserted to check if the task is already complete, in which case the method immediately continues. Or if the task is not complete, a callback is registered to continue execution later, and your method returns.
Returning early is the whole point of an async method.
This question already has answers here:
When should you use Task.Run() rather than await?
(2 answers)
is using an an `async` lambda with `Task.Run()` redundant?
(3 answers)
What difference does it make - running an 'async' action delegate with a Task.Run (vs default action delegate)?
(2 answers)
Closed 3 years ago.
I have some IO-Bound jobs(periodically write some data to file) codes as follows:
public async Task SaveToFile1(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
public async Task SaveToFile2(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
public async Task SaveToFile3(int sleepTimeout)
{
while (true)
{
// Do file saving work
await Task.Delay(sleepTimeout).ConfigureAwait(false);
}
}
The caller is the main method.
The tasks worked fine and produced the correct result when I run them with 2 ways as follows:
void main ()
{
// other codes
// way 1:
SaveToFile1(1000);
SaveToFile2(1000);
SaveToFile3(1000);
// other codes will not let the app exit
}
void main ()
{
// other codes
// way 2:
Task.Run(async() => await SaveToFile1(1000));
Task.Run(async() => await SaveToFile2(1000));
Task.Run(async() => await SaveToFile3(1000));
// other codes will not let the app exit
}
Which is the right way or another way is the best choice for my situation?
Thanks for your answers!
Edit:
In way 1, when await Task.Delay 'complete', a new thread-pool thread may be captured to execute the loop's next step, ..., loop will always running in other thread at the await hit.
In way 2, may be a new thread-pool thread will be used when Task.Run execute immediately, loop will always running in other thread at the begin.
The result are the same, where is the diffrence?
So my question is not about Task.Run vs async-await!
Asynchronous code allows the current thread to be freed to do other work while waiting for a response from something else. But all the code before the first await will be done on the same thread you call it from. If that code is significantly CPU-heavy, it could be noticeable.
If you don't use Task.Run, the method will be run on the same thread up until the first asynchronous I/O request, when it will return a Task and your next method will be called.
Task.Run will execute the code on a different thread. This is good if it does do some CPU-heavy work and you don't want that done on the current thread (like in a desktop app where you don't want it done on the UI thread). But there is a small cost to starting up a new thread too.
Whether using Task.Run will make any noticeable difference depends on the type of app you're writing and what your methods do.
It's fine if you don't await them immediately, but if you don't ever await them, then you will never know when they finished, if they finished successfully, or threw and exception. This is called "fire and forget". Do that only if you don't care if they succeed.
Instead, you can wait at the end to make sure they completed successfully. For example:
void main ()
{
// other codes
var taskList = new List<Task>();
taskList.Add(SaveToFile1(1000));
taskList.Add(SaveToFile2(1000));
taskList.Add(SaveToFile3(1000));
// other codes will not let the app exit
// wait till everything finishes before exiting
await Task.WhenAll(taskList);
}
This question already has answers here:
'await' works, but calling task.Result hangs/deadlocks
(6 answers)
Closed 3 years ago.
In my application, I am trying to update the user profile which calls the Rest API. API has one sync method UpdateProfile where execution getting stuck.
this line of code is ending the execution
command.UserProfile.LookupItems = GetLookupItemsByUserId(existingUser.Id).Result;
When i changed this line of code to
command.UserProfile.LookupItems = Task.Run(async () => await GetLookupItemsByUserId(existingUser.Id)).Result;
It started working without any issue.Can anybody explain to me what is going on behind the scene?
The first version is blocking the current thread, when the task complete the blocked thread cannot catch it.
YourType Signature() {
var neverUsedValue = task.Result;
}
The second one is yielding the current "thread" until the task is returned.
YourType Signature() {
var value = Task.Run(await => async MethodThatWillComplete()).Result
}
What you should do is propagate the async to the method:
async Task<YourType> SignatureAsync() {
command.UserProfile.LookupItems = await GetLookupItemsByUserId(existingUser.Id);
}
In this way you will avoid handling the AggregateException.
There is very well written article on this here:Don't block async
In a few words, blocking on async code is bad because it may be blocking the thread which is supposed to run the async code and thus generete a deadlock.
This question already has answers here:
Task.WaitAll doesn't wait for child task?
(2 answers)
Closed 8 years ago.
Since I was understanding the Task in context of nested task, I really don't understand that- Why the 3rd print before 2nd print?
Even though, I have used Task.WaitAll(t), it print 3rd line before 2nd line.
Code:
public static void Main()
{
Task t = new Task(
() =>
{
Thread.Sleep(2000);
Console.WriteLine("1st print...");
});
t.ContinueWith(
x =>
{
Thread.Sleep(2000);
Console.WriteLine("2nd print...");
},
TaskContinuationOptions.OnlyOnRanToCompletion);
t.Start();
Task.WaitAll(t);
Console.WriteLine("3rd print...");
Console.Read();
}
Output:
You need to wait for the continuation also:
Task t2 = t.ContinueWith( /* .. */ );
Task.WaitAll(new [] { t, t2 } );
You only waited for t, not for its continuation. That's why that continuation will run at some time in the future. If it weren't for the Console.Read it might never run before the process has exited.
Task.WaitAll(t) is equivalent to t.Wait() (which you should use instead because it is more idiomatic).
Having it wait for all continuations (maybe recursively) would make for unintuitive behavior and have non-local effects. Remote parts of the program could influence your code.
You make an assumption that it should wait for child tasks but there is no base to make such assumptions. From MSDN:
Task.WaitAll: Waits for all of the provided Task objects to complete
execution.
And it does exactly what it says. The ContinueWith doesn't change the length of original task, it doesn't become longer. It just executes right after.