Reputation: 5587
I am trying to execute parallel methods, but Form gets stuck whenever I call them.
Please correct what I am doing wrong. Here is the Code:
public partial class Form1 : Form
{
private async void button1_Click(object sender, EventArgs e)
{
var itemList = new List<string>() { "Field1", "Field2", "Field3" };
await Task.WhenAll(itemList.Select(item =>
new WorkToDo(item).StartWork()
));
}
}
public class WorkToDo
{
private string id;
public WorkToDo(string id)
{
this.id = id;
}
public async Task<bool> StartWork()
{
Calculate();
Analyze();
SomeToDo();
var result = Save();
await Task.Delay(100);
return result;
}
private bool Calculate()
{
//Some complex and time taking calculation will be here
return true;
}
private bool Analyze()
{
//Some complex and time taking calculation will be here
return true;
}
private bool SomeToDo()
{
//Some complex and time taking calculation will be here
return true;
}
private bool Save()
{
//Some complex and time taking calculation will be here
return true;
}
}
Upvotes: 3
Views: 1962
Reputation: 203802
The problem that you have is that StartWork
claims to be asynchronous, and yet it isn't. It does all of it's work synchronously.
Marking a method as async
doesn't make it asynchronous. it just allows you to use the await
keyword from within that method. If you perform long running synchronous operations from an async
method then that method is still going to be doing that work synchronously.
There are really two approaches to take here. If there are some number of the things done in StartWork
that really are inherently asynchronous, then you need to wrap whatever synchronous CPU bound work you have in calls to Task.Run
so that the synchronous work that you have can be done asynchronously in a thread pool thread.
If there is no inherently asynchronous operations you have to do in StartWork
then make the method clearly synchronous. Have it return a boolean, not a Task
, and adjust the name to reflect the fact that it is synchronous. Then have the caller that calls it use Task.Run
to do that whole operation on a thread pool thread asynchronously.
Having StartWork
falsely claim to be asynchronous, and then still using Task.Run
to do the purportedly asynchronous work in another thread is going to be extremely confusing to other readers of your code, as there should be no reason to offload an asynchronous method to a non-UI thread.
Upvotes: 2
Reputation: 6142
You need to remember that normal async / await will still be performed on the UI thread.
So to be sure that a real long action is pushed to a background thread, you need to wrap it in Task.Run... like Task.Run(() => Task.WhenAll(tasks));
To complete the question a bit more ( seeing the other answer available ), Task.Run usage is not something to take lightly. It all depends on what sort of code needs to be wrapped. There is a good write up series on this up on the blog of Stephen Cleary here http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-even-in.html so take some time to go through this and see what fits your project.
Or look here for some other details from Stephen https://stackoverflow.com/a/18015586
Upvotes: 4
Reputation: 8263
IMHO, If you are using Async
operation you don't need Task.Run()
if you have Sync Task
and do it asynchronously you need Task.Run()
If you are using normal synchronous process just return
Task<T>
and use thisTask.Run(())
to use background thread to process. See this answer
private async void button1_Click(object sender, EventArgs e)
{
var itemList = new List<string>() { "Field1", "Field2", "Field3" }; // more than 50 items
Task.Run(() => Task.WhenAll(tasks));
}
public class WorkToDo
{
private string id;
public WorkToDo(string id)
{
this.id = id;
}
public async Task<bool> StartWork()
{
var t1 = Calculate();
var t2 = Analyze();
var t3 = SomeToDo();
//Assuming you need to do all this before you save
// so wait for the all.
await Task.WhenAll(t1,t2,t3);
var result = await Save();
return result;
}
private async Task<bool> Calculate()
{
//Some complex and time taking calculation will be here
//Assuming here you have some DoAsync() method
return true;
}
private async Task<bool> Analyze()
{
//Some complex and time taking calculation will be here
return true;
}
private async Task<bool> SomeToDo()
{
//Some complex and time taking calculation will be here
return true;
}
private async Task<bool> Save()
{
//Some complex and time taking calculation will be here
return true;
}
Using WhenAll()
has some advantage like propagating all error at once, see this
Upvotes: 1