Windows 表单卡在多个异步任务上
Windows Form gets stuck on multiple async tasks
我正在尝试执行并行方法,但是每当 Form 卡住
我称他们为.
请指正我做错的地方。这是代码:
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;
}
}
您需要记住,正常的 async / await 仍将在 UI 线程上执行。
因此,要确保将真正的长动作推送到后台线程,您需要将其包装在 Task.Run... 中,例如 Task.Run(() => Task.WhenAll(tasks));
为了进一步完成问题(查看其他可用答案),Task.Run 用法不可轻视。这完全取决于需要包装什么样的代码。
在 Stephen Cleary 的博客 http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-even-in.html 上有一个很好的系列文章,所以花点时间看一下,看看什么适合你的项目。
或在此处查看 Stephen
的其他详细信息
恕我直言,如果您正在使用 Async
操作,则不需要 Task.Run()
如果您有 Sync Task
并且异步执行,则需要 Task.Run()
If you are using normal synchronous process just return Task<T>
and use this Task.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;
}
使用 WhenAll()
有一些优势,比如一次传播所有错误,请参阅 this
您遇到的问题是 StartWork
声称 是异步的,但事实并非如此。它同步完成所有工作。
将方法标记为 async
不会使其成为异步的。它只允许您在该方法中使用 await
关键字。如果您从 async
方法执行长 运行 同步操作,那么该方法仍将同步执行该工作。
这里实际上有两种方法。如果在 StartWork
中完成的一些事情实际上本质上是异步的,那么您需要包装任何同步 CPU 绑定工作,您在调用 Task.Run
时进行绑定,以便同步工作您可以在线程池线程中异步完成。
如果在 StartWork
中没有必须执行的固有异步操作,那么 使方法明确同步 。让它 return 一个布尔值,而不是 Task
,并调整名称以反映它是同步的。然后让调用它的调用者使用 Task.Run
在线程池线程上异步执行整个操作。
StartWork
错误地声称是异步的,然后仍然使用Task.Run
来据称另一个线程中的异步工作会让代码的其他读者非常困惑,因为没有理由将异步方法卸载到非 UI 线程。
我正在尝试执行并行方法,但是每当 Form 卡住 我称他们为.
请指正我做错的地方。这是代码:
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;
}
}
您需要记住,正常的 async / await 仍将在 UI 线程上执行。
因此,要确保将真正的长动作推送到后台线程,您需要将其包装在 Task.Run... 中,例如 Task.Run(() => Task.WhenAll(tasks));
为了进一步完成问题(查看其他可用答案),Task.Run 用法不可轻视。这完全取决于需要包装什么样的代码。 在 Stephen Cleary 的博客 http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-even-in.html 上有一个很好的系列文章,所以花点时间看一下,看看什么适合你的项目。
或在此处查看 Stephen
的其他详细信息恕我直言,如果您正在使用 Async
操作,则不需要 Task.Run()
如果您有 Sync Task
并且异步执行,则需要 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;
}
使用 WhenAll()
有一些优势,比如一次传播所有错误,请参阅 this
您遇到的问题是 StartWork
声称 是异步的,但事实并非如此。它同步完成所有工作。
将方法标记为 async
不会使其成为异步的。它只允许您在该方法中使用 await
关键字。如果您从 async
方法执行长 运行 同步操作,那么该方法仍将同步执行该工作。
这里实际上有两种方法。如果在 StartWork
中完成的一些事情实际上本质上是异步的,那么您需要包装任何同步 CPU 绑定工作,您在调用 Task.Run
时进行绑定,以便同步工作您可以在线程池线程中异步完成。
如果在 StartWork
中没有必须执行的固有异步操作,那么 使方法明确同步 。让它 return 一个布尔值,而不是 Task
,并调整名称以反映它是同步的。然后让调用它的调用者使用 Task.Run
在线程池线程上异步执行整个操作。
StartWork
错误地声称是异步的,然后仍然使用Task.Run
来据称另一个线程中的异步工作会让代码的其他读者非常困惑,因为没有理由将异步方法卸载到非 UI 线程。