【问题标题】:C# .NET Tasks: How to get notification when multiple tasks have completedC# .NET 任务:如何在多个任务完成时获得通知
【发布时间】:2011-08-04 14:49:11
【问题描述】:

在我的 WPF 应用程序中,我需要并行运行 2 个长时间运行的任务,它们都返回需要在 UI 中显示的数据。

我的视图模型中有一个名为 IsBusy 的属性,在这两个任务完成之前它应该为真。

如何在 2 个长时间运行的任务完成后收到通知?

我不想使用 Task.WaitAll,因为它会阻塞我的 UI 线程。我不想使用 ContinueWith 链接任务,因为我希望那些长时间运行的任务并行运行。

【问题讨论】:

    标签: .net .net-4.0 task


    【解决方案1】:

    使用 TaskScheduler.FromCurrentSynchronizationContext() 并将其传递给 TaskFactory.ContinueWhenAll(...) 在两个任务完成后进行 UI 更新。

    【讨论】:

    • 这正是我要找的。我怀疑框架中有这样的东西,我只是找不到。
    【解决方案2】:

    一种方法是创建第三个线程来生成这些任务,并使用Task.WaitAll 延迟线程退出,直到两个任务完成。在该线程结束时,您可以触发事件或执行回调函数。

    您可以使用BackgroundWorker 来简化它,它有一个名为RunWorkerCompleted 的内置事件。这将使您进入线程池,因此您不必担心管理该线程。

    【讨论】:

      【解决方案3】:

      试试Task.Factory.ContinueWhenAll。它需要一个 Tasks 数组,并在它们全部完成时异步触发一个操作。

      【讨论】:

        【解决方案4】:

        如果有一个对应于每个任务的布尔标志,以及另一个监控这些标志的单独的观察者线程呢?让每个任务在从处理中返回时设置其相应的标志。然后,监控线程观察是否设置了标志(即两个任务都已完成)。如果进程已完成,则触发一个事件,将 IsBusy 设置为 false,等等。

        【讨论】:

          【解决方案5】:

          我认为你的回答是回调。

          设置长时间运行的线程时,请传入对方法的引用。您可以将回调方法传递给任务方法,也可以设置一个 AsyncCallback 委托实例,该实例内置于委托的 BeginInvoke() 功能中。

          这是一个基本的例子:

          public void StartMyTwoTasks()
          {
             //I'm passing the callback to the task method directly; you may prefer to pass it to BeginInvoke()
             var task1Lambda = ()=>Task1(TaskCompleted);
             var task2Lambda = ()=>Task2(TaskCompleted);
          
             task1Lambda.BeginInvoke(null,null);
             task2Lambda.BeginInvoke(null,null);
          }
          
          public void Task1(Action<int> task1Complete)
          {
             //perform your long-running calculation or data retrieval/transformation here
             Thread.Sleep(10000);
             //when finished, call the callback method.
             //You may need to use Control.Invoke() to make sure the callback is executed on the UI thread
             //If you use the AsyncCallback feature of BeginInvoke/EndInvoke, you don't have to make the call here.
             taskComplete(1);
          }
          
          public void Task2(Action<int> taskComplete)
          {
             //Ditto
             Thread.Sleep(8000);
          
             taskComplete(2);
          }
          
          public void Task1Complete(int taskNumber)
          {
             TasksComplete[taskNumber-1] = true;
             If(TasksComplete.All(x=>x==true))
                DoSomethingOnceAllTasksAreComplete();
          }  
          

          使用 AsyncCallback 功能,您的回调方法必须符合接受 IAsyncResult 的特定委托定义,但您不必担心在您的方法中正确调用它;框架为您处理回调:

          public public void StartALongTask()
          {
             var taskLambda = ()=>PerformTask();
          
             taskLambda.BeginInvoke(TaskComplete,null);
          }
          
          //one advantage is that you can call a method that returns a value very easily.
          public IEnumerable<string> PerformTask()
          {
              //long-running task
              Thread.Sleep(5000);
          
              return Enumerable.Repeat("result", 100);
          
              //look ma, no callback invocation. 
              //This makes asynchronous delegates very useful for refactoring a synchronous 
              //operation without a lot of code changes.
          }
          
          //Here's the callback, which is invoked properly by the runtime when the thread is complete
          public void TaskComplete(IASyncResult ar)
          {
              //calling EndInvoke on the same delegate, which is available in the AsyncResult,
              //returns the return value of that delegate as if you'd called it synchronously.
              var results = ar.AsyncDelegate.EndInvoke(ar);
          
              //Now you can do something with those results.
          }
          

          这两种模型都应该适合您。其他选项包括设置一个事件,然后在完成时由每个方法引发。它的工作方式几乎相同,因为事件实际上只是带有一些语法糖的“多播”委托。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-03-07
            • 1970-01-01
            • 1970-01-01
            • 2015-10-20
            • 1970-01-01
            相关资源
            最近更新 更多