【问题标题】:Parallel For and background worker并行 For 和后台工作者
【发布时间】:2016-09-15 20:07:01
【问题描述】:

我有这个简单的:

        for (int i = 0; i < nro_archivos; ++i) //Cargar el objeto img
        {
            string nombrearchivo = archivosdicom[i].FullName;
            img.Add(new ImagenDicom(nombrearchivo));
            Progress_Bar_Loading_Images.PerformStep();
        }

接下来是:

   decimal[] sliceseparation_imagen = new decimal[img.Count - 1];
        for (int i = 0; i < img.Count; i++)
        {
            if (i < img.Count - 1)
            {
                sliceseparation_imagen[i] = Math.Abs(img[i + 1].Z - img[i].Z);
            }
        }
        sliceseparation_promedio = sliceseparation_imagen.Average();

现在,我的挑战是: 我实现了Paralell For但不能使用进度条..所以我在考虑使用BackgroundWorker但问题是for之后的操作取决于在for中发生的对象img的负载,直到没有完成我无法继续。 我对BackGroundWorker的理解是,它在后台执行,而主程序继续执行,所以这种方式在尝试访问到主程序到达for之外的代码时还没有创建的img对象时会带来错误。

在这种情况下是否值得使用Background Worker来加速img对象的加载?如果是这样,我如何等到后台工作人员完成其工作后再继续执行主程序?我需要向用户报告 for 操作的进度,因此在没有允许我向用户报告的情况下使用并行 for 是行不通的。 谢谢, 马蒂亚斯。

【问题讨论】:

  • Background Worker 的一个特点是它的目的是在后台执行长时间的计算工作,而 UI 的更新可以通过主线程来处理。您可以处理 DoWork、ProgressChanged 等事件 - 报告可用于在您的案例中更新 Progressbar 的状态
  • 谢谢奥斯汀,这对我来说很好,问题在于继续在主线程中执行的代码,它使用正在加载的对象 for(将在后台worker 如果我决定实现它)所以在它没有完成之前,我真的不能做太多,否则它会在尝试访问尚未加载的对象时抛出错误

标签: c# winforms parallel-processing backgroundworker parallel.for


【解决方案1】:

如果我理解这里的问题,当你加载图像时你有一组工作,你可以不关心这个,假装这无论如何都可以并行发生,但问题是你需要报告进度。

在加载它之后,您还需要完成另一项工作,您可以立即执行,也可以在加载所有图像后执行。

您可以选择任务,而不是并行。通过 UI 调度程序访问 UI 线程,因此您不必担心 UI 线程访问问题。

var tasks = new List<Task>
{
    Task.Run(() => { 
     // Block 1 
     // Use a proper dispatcher here to access the UI thread so you can report your progress}),
};
Task.WaitAll(tasks);

现在你已经完成了你的工作,你可以继续你的第二个工作。

但是,正如我所见,您只需要其中的average,并且您不需要正确的顺序来获得平均。

    var tasks = new List<Task>
        {
            Task.Run(() => { /* for loop logic #1 */})
            .ContinueWith((x)=> {
                // Get your task result and execute second block 
            })
        };
   Task.WaitAll(tasks);

现在你有一个持续的任务,你所要做的就是在完成后调用一个平均值。

您也可以使用两个单独的块。我想既然这些任务是相互交织的,为什么你不能继续做一项任务呢。

【讨论】:

    【解决方案2】:

    使用任务可能会有所帮助

    var tasks = new List<Task>
    {
        Task.Run(() => { /* for loop logic #1 */
                /* when interacting w/UI either use Dispatcher
                   for WPF for control.Invoke in winforms */
            }),
        Task.Run(() => { /* for loop logic #2 */})
    };
    Task.WaitAll(tasks.ToArray());
    

    【讨论】:

    • 这可能有效,但我仍然遇到使用进度条报告进度的问题。它将从主线程外部访问它,从而导致错误。
    • 更新进度条时,在UI线程调用,避免跨线程异常。有不同的方法可以做到这一点(wpf vs winforms等)以下链接可能会有所帮助。 stackoverflow.com/questions/661561/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多