在我的WPF应用程序中,我需要并行运行2个长时间运行的任务,这两个任务都返回需要在UI中显示的数据。
我的视图模型中有一个名为IsBusy的属性,在两个任务完成之前都应为true。
如何在2个长时间运行的任务完成后收到通知?
我不想使用Task.WaitAll,因为它会阻止我的UI线程。我不想使用ContinueWith链接任务,因为我希望这些长时间运行的任务并行运行。
答案 0 :(得分:5)
使用TaskScheduler.FromCurrentSynchronizationContext()并将其传递给TaskFactory.ContinueWhenAll(...),以便在两个任务完成后进行UI更新。
答案 1 :(得分:4)
一种方法是创建产生这些任务的第三个线程,并使用Task.WaitAll
来延迟线程退出,直到两个任务完成。在该线程结束时,您可以触发事件或执行回调函数。
使用名为BackgroundWorker的内置事件RunWorkerCompleted可以让您更轻松。这会让你进入线程池,所以你不必关心管理那个线程。
答案 2 :(得分:4)
试试Task.Factory.ContinueWhenAll
。它需要一个Tasks
数组,并在它们全部完成时异步触发一个操作。
答案 3 :(得分:0)
我认为你的答案是回调。
设置长时间运行的线程时,传入对方法的引用。您可以将回调方法传递给任务方法,也可以设置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.
}
这两种型号都应该适合你。其他选项包括设置事件,然后在完成时由每个方法引发。它的工作方式几乎相同,因为事件实际上只是具有一些语法糖的“多播”代理。
答案 4 :(得分:0)
如果有一个与每个任务相对应的布尔标志,另一个单独的观察者线程监视这些标志呢?让每个任务在从处理返回时设置相应的标志。然后,监视线程监视是否设置了标志(即两个任务都已完成。)如果进程完成,则触发事件,将IsBusy设置为false等。