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

Result now shown in UI until all tasks are finished even though I am adding in UI as individual task completes

在我的 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

编辑
更新代码,更详细地说明我的任务数组是如何创建的

如果您使用的是 .NET 4.0,则可以使用延续。您不需要 while 循环在 UI 线程中等待获得结果,因为 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

有很多问题,假设此方法在 UI 线程上运行:

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

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

  3. 不清楚 RunSomeMethod 做了什么,但正如它 returns Task<string> 的含义是它 returns 没有完成并且异步完成。如果它在返回任务之前实际上没有做任何工作,那么我看不到 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);
}