簡體   English   中英

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

您需要記住,仍然會在UI線程上執行正常的async / await。

因此,為了確保將一個真正的長動作推送到后台線程,您需要將它包裝在Task.Run中...就像Task.Run(() => Task.WhenAll(tasks));

為了更多地完成這個問題(看到其他答案可用),Task.Run的使用並不是一件容易的事情。 這一切都取決於需要包裝的代碼類型。 斯蒂芬·克利里(Stephen Cleary)的博客上有一篇很好的寫作系列http://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-even-in.html因此需要一些時間來完成這個看看你的項目是什么。

或者在這里查看Stephen 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()具有一次傳播所有錯誤的優點,請參閱

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM