首頁>Program>source

好吧,所以基本上我有很多工(10),我想同時啟動所有任務並等待它们完成.完成後,我想執行其他任務.我讀了很多有關此的資源,但是我無法针對我的具體情况...

這是我目前拥有的(代碼已簡化):

public async Task RunTasks()
{
    var tasks = new List<Task>
    {
        new Task(async () => await DoWork()),
        //and so on with the other 9 similar tasks
    }

    Parallel.ForEach(tasks, task =>
    {
        task.Start();
    });
    Task.WhenAll(tasks).ContinueWith(done =>
    {
        //Run the other tasks
    });
}
//This function perform some I/O operations
public async Task DoWork()
{
    var results = await GetDataFromDatabaseAsync();
    foreach (var result in results)
    {
        await ReadFromNetwork(result.Url);
    }
}

所以我的問题是,当我等待任務完成時, 呼叫,它告诉我所有任務都結束了,即使它们都没有完成.我尝試添加 WhenAll 在我的飞天 当我輸入繼續任務時,資料不斷从我以前的 Console.WriteLine中輸入 尚未真正完成。

我在這裏做什麼錯了?

foreach
最新回復
  • 5月前
    1 #

    您几乎永远都不要使用 Task 直接構造函式.對於您而言,该任務只会觸發您迫不及待的實際任務。

    您可以簡單地致電 DoWork 然後取迴任務,將其儲存在列表中,然後等待所有任務完成.含義:

    tasks.Add(DoWork());
    // ...
    await Task.WhenAll(tasks);
    

    但是,異步方法將同步執行,直到第一次等待未完成的任務.如果您担心该部分花费的時間太长,請使用 Task.Run 將其卸載到另一个 ThreadPool 執行緒,然後儲存 that 列表中的任務:

    tasks.Add(Task.Run(() => DoWork()));
    // ...
    await Task.WhenAll(tasks);
    

  • 5月前
    2 #

    本質上,您是在混合两種不相容的異步範例; 即 Parallel.ForEach()async-await

    對於您想要的,執行一項或另一項.例如.你可以只用 Parallel.For[Each]() 並完全删除異步等待. Parallel.For[Each]() 仅在所有並行任務完成後才返迴,然後您可以移至其他任務。

    代碼也有其他一些問题:

      you mark the method async but don't await in it (the await you do have is in the delegate, not the method);

      you almost certainly want .ConfigureAwait(false) 隨時待命,特別是如果您不想立即在UI執行緒中使用結果。

      p

      如果要使用TPL在不同的執行緒中並行執行這些任務,則可能需要這樣的东西:

      public async Task RunTasks()
      {
          var tasks = new List<Func<Task>>
          {
             DoWork,
             //...
          };
          await Task.WhenAll(tasks.AsParallel().Select(async task => await task()));
          //Run the other tasks
      }
      

      這些方法仅並行處理少量代碼:將方法排队到執行緒池中以及返迴未完成的 Task .同樣,對於如此少量的任務,並行化可能比異步執行花费更多的時間.仅当您的任務在第一次等待之前做一些更长的(同步)工作時,這才有意義。

      在大多數情况下,更好的方法是:

      public async Task RunTasks()
      {
          await Task.WhenAll(new [] 
          {
              DoWork(),
              //...
          });
          //Run the other tasks
      }
      

      在您的代碼中,我认為:

      您不應將代碼包裝在 Task中 在傳遞到 Parallel.ForEach之前

      您可以 await Task.WhenAll 而不是使用 ContinueWith

  • 5月前
    3 #

    DoWork method是異步I / O方法.這意味着您不需要多个執行緒来執行其中的几个執行緒,因為在大多數情况下,该方法將異步等待I / O完成.一个執行緒就足以做到這一點。

    public async Task RunTasks()
    {
        var tasks = new List<Task>
        {
            DoWork(),
            //and so on with the other 9 similar tasks
        };
        await Task.WhenAll(tasks);
        //Run the other tasks            
    }
    

    几乎不應该使用 Task 構造函式来建立新任務.要建立異步I / O任務,只需呼叫 async 方法.要建立將線上程池執行緒上執行的任務,請使用 Task.Run .您可以阅讀這篇文章,详细了解 Task.Run 以及建立任務的其他選項。

  • 5月前
    4 #

    還可以在Task.whenAll

    週圍添加一个try-catch塊。

    NB:丟擲System.AggregateException的一个例項,该例項充当已發生的一个或多个異常的包裝.這對於協調多个任務(例如Task.waitAll()和Task.waitAny())的方法很重要,以便AggregateException能够將所有異常包裝在已發生的執行任務中。

    try
    { 
        Task.WaitAll(tasks.ToArray());  
    }
    catch(AggregateException ex)
    { 
        foreach (Exception inner in ex.InnerExceptions)
        {
        Console.WriteLine(String.Format("Exception type {0} from {1}", inner.GetType(), inner.Source));
        }
    }
    

  • 在C ++中的變數宣告中使用struct關鍵字
  • python:pandas時代三角洲