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;
    }
}

Windows 窗体卡在多个异步任务上

您需要记住,正常的异步/等待仍将在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() 有一些优点,例如一次传播所有错误,请参阅此处