结果现在显示在 UI 中,直到所有任务都完成,即使我在单个任务完成时在 UI 中添加

本文关键字:任务 UI 添加 单个 完成时 显示 结果 | 更新日期: 2023-09-27 18:36:04

在我的WPF应用程序中,我正在使用任务在单独的线程中进行一些后台处理。之后,当我开始从这些任务中获取结果时,我将结果更新到列表框中。除了每个任务完成时结果不会写入列表框之外,一切都运行良好。一旦我的任务数组中的所有项目都完成后,所有结果都会写入列表框,因此用户基本上无法看到我们收到这些结果的结果。相反,他们必须等到最后一个任务完成,然后才能在该列表框中显示任何内容。下面是我遇到问题的相关代码的一小部分。整个事情太大了,有很多不相关的东西不能在这里展示。我在代码中做错了什么导致这种延迟吗?

Task<String>[] myTasks = myListWithData.AsParallel().WithDegreeOfParallelism(10).Select( x => RunSomeMethod(x)).ToArray();

// Here I am back at the UI thread
         while ( myTasks.Length > 0 )
         {
             try
             {
                 int i = Task.WaitAny(myTasks);
         string Result = myTasks[i].Result;
                 this.lst1.Items.Add(Result);  // result is been added in the listbox. It should be available now??
                 // here is my logic for removing task with index i from myTasks
             }
             catch (Exception ex)
             {
             }
         }   
// At this point, user gets to see results for all tasks in that listbox

编辑
更新代码,其中包含有关如何创建任务数组的更多详细信息

结果现在显示在 UI 中,直到所有任务都完成,即使我在单个任务完成时在 UI 中添加

假设此方法在 UI 线程上运行,则存在许多问题:

  1. 此方法阻止。 在此方法完成之前,UI 不会更新,这将在所有任务完成后更新。

  2. Parallel/PLINQ将使用调用线程作为并行处理线程之一,因此这也将阻塞。

  3. 目前尚不清楚RunSomeMethod做什么,但是当它返回Task<string>时,这意味着它返回而不完成并且异步完成。 如果它在返回任务之前实际上没有做任何工作,那么我看不到MaxDegreeOfParallelism(10)实际上在做任何事情:所有任务都将几乎立即创建(并在创建时阻止)。

假设为 .NET 4.5,这将解决大多数问题。 如果需要调用方法(对于其他代码),Task.WhenAll则需要将调用方法标记为async

var tasks = myListWithData.Select(ProcessAsync).ToArray();
await Task.WhenAll(tasks);
// continue

ProcessAsync定义如下,假设RunSomeMethodThreadPool线程上执行:

private async Task ProcessAsync(string data)
{
    var result = await RunSomeMethod(data);
    lst1.Items.Add(result);
}

如果你使用的是 .NET 4.0,则可以使用延续。无需在 UI 线程中等待 while 循环获取结果,因为Task.WaitAny会阻塞线程。

.NET 4.0

for(var i=0; i < taskCount; ++i)
{
    Task.Factory.StartNew(() => // some long running stuff which returns string)
                .ContinueWith(t => this.lst1.Items.Add(t.Result),
                              TaskScheduler.FromCurrentSynchronizationContext()); 
}

对于 .Net 4.5 或更高版本,您可以按照建议@SLaks使用await