C# .NET:同步长时间运行任务的机制

C# .NET:同步长时间运行任务的机制,c#,multithreading,user-interface,asynchronous,synchronization,C#,Multithreading,User Interface,Asynchronous,Synchronization,问题描述:您编写了一个库,其中包含一些可能需要很长时间才能完成的算法/任务,原因多种多样:计算、文件系统、网络通信等。您希望能够: 发送有关任务的一些进度信息(进度、活动日志等) 如果设置了某些外部信号或属性,可以在任务完成之前中止任务 我已经为此实现了一个框架,但这要求所有此类任务都必须引用包含此框架的程序集 我的问题:对于上述问题,.NET framework(3.5或更低版本)中是否已有内置机制? 我知道我可以使用事件,但这意味着长时间运行的任务必须公开此类事件,我认为这是一种开销。理想情

问题描述:您编写了一个库,其中包含一些可能需要很长时间才能完成的算法/任务,原因多种多样:计算、文件系统、网络通信等。您希望能够:

  • 发送有关任务的一些进度信息(进度、活动日志等)
  • 如果设置了某些外部信号或属性,可以在任务完成之前中止任务
  • 我已经为此实现了一个框架,但这要求所有此类任务都必须引用包含此框架的程序集

    我的问题:对于上述问题,.NET framework(3.5或更低版本)中是否已有内置机制?

    我知道我可以使用事件,但这意味着长时间运行的任务必须公开此类事件,我认为这是一种开销。理想情况下,我希望有一个隐藏多线程问题的框架,并且是依赖注入友好的,但不依赖于额外的自定义程序集,也不会污染原始接口

    我希望我对这个问题描述得足够好。如果没有,我可以从我自己的框架发布一些接口示例

    更新:好的,我想我的问题描述需要澄清一下:)。当我说“长时间运行”时,我不是指工作流意义上的“长时间”。我正在开发一个WinForms映射应用程序,它可以做各种事情,比如生成。为此,它首先必须从FTP服务器下载高程数据文件,解压缩它们,然后执行一些计算。我很久以前就为此编写了代码,但为了使它更友好,我必须重新适应各种检查-例如,检测到用户单击了中止按钮并停止进程


    因此,基本上我关心的是:如何编写一个以后(如果有的话)可以在GUI环境中使用的代码,在GUI环境中,您不能简单地运行主GUI线程中的所有内容并冻结整个应用程序挑战在于找到一种方法,使您的代码适合GUI用途,而无需将其绑定到特定的GUI平台。

    这听起来很像。

    看看saga模式。它没有内置到框架中,但可以实现。或者,NServiceBus和MassTransit都实现了这一点。阿农·尔戈(Arnon RGO)有一本书的草稿(它是否会完成)描述了它

    根据我的经验,使用NServiceBus比WF简单得多,而且功能也更强大(尽管我还没有看过WF 4,所有的描述都是对WF的近乎完全的修改,因为微软已经意识到了它的缺陷)


    即使您不想要像NServiceBus或MassTransit这样的框架,模式本身也很值得一看,因为它与您描述的问题空间非常接近。

    这取决于您的系统有多复杂。对于相对简单的问题,可以很好地使用.NET2.0中的。它支持使用
    OnProgressChanged
    事件报告操作进度,还支持使用
    CancelAsync
    方法取消后台任务

    该类由事件控制,但由于这已经是该类的一部分,我不认为这会给您带来任何开销:

    var bw = new BackgroundWorker();
    bw.DoWork += new DoWorkEventHandler(DoWork);
    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(RunWorkerCompleted);
    bw.ProgressChanged += new ProgressChangedEventHandler(ProgressChanged);
    
    • 执行
      DoWork
      方法以运行后台任务(它可以通过调用
      bw.ReportProgress
      报告进度,并使用
      bw.CancellationPending
      检查挂起的取消)

    • 当操作完成时,
      RunWorkerCompleted
      方法在GUI线程上执行(这为您提供了一种很好的同步方法,而不必担心并发性)

    • 每当
      DoWork
      方法报告某些进度更改时,就会触发
      ProgressChanged
      事件


    对于更简单的问题,我相信您可以将您的任务表示为后台工作人员。

    我更喜欢使用回调方法在某些事情完成或进度需要更新时向UI线程发出信号。您可以传递复杂对象,回调可以返回一个值,以防它需要向工作线程发送信号。您还可以根据需要员工的健谈程度定义多个回调。

    第一个想法\u您可以考虑使用System.Diagnostics.PerformanceCounter进行数字活动日志记录。然后,任何知道其名称的应用程序都可以读取数据。要发出中止信号,可以将EventWaitHandle与命名句柄一起使用。这两种方法都不需要dll链接,但它们需要共享的“字符串”命名。或者像@mark建议的那样走WWF路线。我希望避免“干净、无辜”的库代码与诸如等待句柄、线程和WMI等棘手的代码混为一谈;)我正在寻找这些模式的抽象(最好是通过C#接口,使其更易于测试)。WWF对于我所描述的问题来说有点过火(我已经更新了描述)。@Tomas,我已经使用BackgroundWorker来实现这些目的,但间接地是在基础架构级别。问题是,将您的任务直接表示为BackgroundWorker类意味着它将始终以异步模式运行,但情况并非如此。是的,我希望BackgroundWorker在您的情况下功能不够强大。希望它能帮助人们在未来更简单的环境中解决这类问题。