关于并发处理所需的设计思路

时间:2013-02-05 14:20:57

标签: c# .net concurrency

我有一系列需要处理的计算 - 计算及其运行的顺序都是由用户在UI上定义的。

如果他们只是一个接一个地跑,那就不会太难了。但是,某些计算需要同时处理,并且所有计算必须能够随时单独暂停。我还需要能够随时重新安排订单或添加新的计算。所以无论我做什么,都必须足够灵活,以便处​​理这个问题。

在用户界面上,想象一下用户控件的列表框(队列,如果你愿意) - 每个用户控件显示计算名称和暂停按钮。我可以在处理过程中随时向此列表添加计算。

这样做的最佳方式是什么?

我应该在自己的线程中运行每个计算吗?如果是这样,我应该如何存储正在运行的进程列表?如何将队列传递给计算处理器?我怎样才能确保每次队列更改(新订购或新计算)时计算处理器都会知道这个?

我最初的想法是:

  • CalcProcessor class
  • CalcCalculation class

CalcProcessor中有2 Lists CalcCalculations。一个是UI上显示的“队列”(可能是指向它的指针?或其他一些确保它实时更新的方式),另一个是当前正在运行的计算列表。

不知何故,我需要让CalcCalculation在自己的线程中运行来处理计算,并能够处理任何暂停事件。所以我需要一些方法将UI中按下的暂停按钮的信息传送到CalcProcessor对象,然后传送到正确的CalcCalculation

编辑回应David Hope:

感谢您的回复。

  1. 是的,有n个计算,但由于能够在UI上添加更多计算以进行处理,因此可能会随时更改。

  2. 他们无论如何都不需要共享数据。应用程序中将有一个设置来指定应该并发运行的数量(例如,在任何给定时间为10,例如队列中的前10个 - 当1结束时,队列中的下一个计算将开始处理)。

  3. 计算将涉及从某些数据源获取数据 - 它可以是数据库或文件,并分析它并对该数据执行一些计算。当我说计算需要暂停时,我并不是说暂停线程...我只是意味着(例如,因为我还没有编写应用程序的这一部分)如果它是从一行逐行读取数据库并进行一些实时计算在处理当前行时完成暂停...并继续在UI上单击暂停按钮时 - 这可以通过原始作为一段时间(notPaused)循环提供我可以获得将UI中的信息暂停到线程中。

5 个答案:

答案 0 :(得分:2)

这里有几个问题:

如何同步UI和模型?

我认为你倒退了这个。您的模型不应该具有指向您在UI中显示的队列的“指针”。相反,队列应该在您的模型中,您应该与INotifyPropertyChangeObservableCollection一起使用数据绑定来显示UI上的队列。 (至少这是在WPF中完成的。)

这样,您可以直接从模型中操作队列,它将自动显示在UI上。

如何启动和监控计算?

我认为Task是理想的。您可以使用Task开始Task.Factory.StartNew()。由于您的Task似乎需要很长时间才能执行,因此您可以考虑使用TaskCreationOptions.LongRunning。您还可以使用Task找出计算完成的时间(或者如果失败并出现异常)。

如何暂停运行计算?

您可以使用ManualReserEventSlim。通常,它会被设置,但是如果你想暂停一个正在运行的Task,你会Reset()它。计算需要定期在该事件上调用Wait()。如果没有与该线程的计算合作,就不可能合理地暂停正在运行的线程。

如果您使用的是C#5.0,更好的方法是使用PauseToken之类的内容。

答案 1 :(得分:0)

在Framework 4.5中,这里的答案是Async API,它消除了管理线程的需要。有关详情,请查看the async/await个关键字。

从更广泛的角度来看,“CalcProcessor”类是一个好主意,但我认为Task对象足以替换你的“CalcCalculation”类。处理器可以简单地具有可枚举的任务。如果需要,处理器可以公开管理队列的方法,以及返回有关其状态的信息。当您的应用程序最终达到必须具有结果的状态时,您可以使用AwaitAll方法来阻止CalcProcessor的线程,直到所有任务完成。

如果没有关于实际目标的更多信息,很难提供更好的建议。

答案 2 :(得分:0)

您可以使用Observer Pattern在UI上显示结果,并将订单更改回处理器。 StateCommand模式将帮助您启动,暂停,取消计算。这些模式在设计方面对您的问题有很好的答案。并发仍然是一个问题,它们不能解决多线程问题,但它们为管理线程开辟了一条更容易的道路。

答案 3 :(得分:0)

我建议你没有把问题彻底解决,这就是你感到沮丧的原因。

你需要从小处开始,然后从那里开始建立。你提到,但没有定义你的实际要求,但它们似乎是......

  1. 需要能够跑?N?计算
  2. 有些需要同时运行(这是否意味着他们共享数据,如果是这样,你将如何共享数据)
  3. 必须能够暂停计算(不要使用Thread.Suspend,因为它可能使线程处于不稳定状态,如果共享数据则特别糟糕),因此您需要在每次计算中构建暂停点。还需要考虑如何将暂停/取消暂停与计算进行通信
  4. 就方法而言,有几个需要考虑......

    线程是一个明显的选择,但也需要小心谨慎(开始,暂停,停止等......)

    您也可以使用BackGroundWorker或者可能使用Parallel.ForEach

    BackGroundWorker包含取消工作人员和提供进度的框架(可能很有用)。

    我的建议是使用BackGroundWorker,可能将其子类化以添加您需要的暂停/恢复功能。确定如何管理数据共享(至少使用锁定以防止同时访问)。

    您可能会发现BackGroundWorker限制性太强,需要使用Threads,但我通常可以避免使用它。

    如果您发布更明确的要求,或者您尝试过但没有效果的样本,我将很乐意提供更多帮助。

答案 4 :(得分:0)

对于队列,您可以使用堆数据结构(优先级队列)。这将有助于优先处理您的任务。您还应该使用线程池进行有效计算。并尝试将任务分成几个部分。