Windows 窗体卡在多个异步任务上
本文关键字:异步 任务 窗体 Windows | 更新日期: 2023-09-27 18:33:55
我正在尝试执行并行方法,但每当表单卡住时我打电话给他们。
请纠正我做错了什么。这是代码:
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;
}
}
您需要记住,正常的异步/等待仍将在UI线程上执行。
因此,为了确保将真正的长操作推送到后台线程,您需要将其包装在 Task.Run...喜欢Task.Run(() => Task.WhenAll(tasks));
为了进一步完成这个问题(看到其他可用的答案(,Task.Run 的使用不能掉以轻心。这完全取决于需要包装哪种代码。在Stephen Cleary的博客上有一个很好的系列文章,所以 http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-even-in.html 花一些时间浏览一下,看看什么适合你的项目。
或者在这里查看斯蒂芬·https://stackoverflow.com/a/18015586 的其他细节
你遇到的问题是StartWork
声称是异步的,但事实并非如此。 它同步完成所有工作。
将方法标记为async
不会使其异步。 它只允许您从该方法中使用 await
关键字。 如果从 async
方法执行长时间运行的同步操作,则该方法仍将同步执行该工作。
这里实际上有两种方法可以采取。 如果在StartWork
中完成的一些事情本质上是异步的,那么您需要在调用 Task.Run
中包装您拥有的任何同步 CPU 密集型工作,以便您拥有的同步工作可以在线程池线程中异步完成。
如果没有必须在StartWork
中执行固有的异步操作,则使该方法明确同步。 让它返回布尔值,而不是Task
,并调整名称以反映它是同步的事实。 然后让调用它的调用方使用 Task.Run
异步对线程池线程执行整个操作。
让StartWork
错误地声称自己是异步的,然后仍然使用 Task.Run
在另一个线程中执行所谓的异步工作,这会让代码的其他读者感到非常困惑,因为应该没有理由将异步方法卸载到非 UI 线程。
我直言,如果您使用的是Async
操作,则不需要Task.Run()
如果您有Sync Task
并异步执行,则需要Task.Run()
如果您使用的是普通同步进程,只需返回
Task<T>
并使用此Task.Run(())
使用后台线程进行处理。查看此答案
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;
}
使用 WhenAll()
有一些优点,例如一次传播所有错误,请参阅此处