zoukankan      html  css  js  c++  java
  • ERP/MIS 开发 多线程模式与应用(开放源码)

    一直从事ERP/MIS开发,总结一下,自己在ERP/MIS开发中,经常用到的应用多线程的两种模式。

    先举一个例子,以帮忙回忆起对多线程的印象。CopyFilesProc是实现拷贝文件的一个方法,用多线程调用:

      Thread simpleThread = new Thread(CopyFilesProc);

      simpleThread.Name = "CopyFiles";

      simpleThread.Start();

    启动调用,在VS2010中,增加了线程调试窗口,以查看当前进程的线程。我的理解是,总是记得给你的线程命名。

    image

    1 需要与界面互动的场景,需要实现报告进度,应用BackgroundWorker组件

    image

    如图,月结的界面效果图,当用户点击Process按钮后,出现进度条,显示处理进度
    对于BackgroundWorker控件的运用,请查阅MSDN知识库。我这里对报告进度这一小功能,作说明。

    报告进度的功能,分两种情况来实现。一种是处理任务(Job)没有用接口实现,当前进度变量存在于窗体中,源码如下

    private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
           {
               bgWorker.ReportProgress(10, fileName);            
            }

    直接在DoWork事件中,调用ReportProgress方法,如果可能,还可以传入变量值

    private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
           {
               string fileName = e.UserState.ToString();
            }

    注册事件ProgressChanged来输出当前正在处理的项目,在这个方法中可以操作UI控件。

    另一种方法是,处理任务的实现(Job的功能实现)被隔离到第三方的类库中,说白了就是放到外部的类文件中,不与窗体代码混淆在一起。代码举例,对于月结功能,可能的一个这样的实现

    public interface IJob
        {
            void Execute();
         }

    实现文件

    public class Job : IJob
       {

         public void Execute()
           { 

           }

        }

    在窗体的bgWorker_DoWork方法中,调用实现job.Execute()来这现月结功能。

    这种方法下,报告进度的功能稍微复杂一点,要用到定时器,进度存放变量值,执行任务时更新进度。
    实现步骤如下,在接口实现文件,定义存放进度变量的集合值_JobProcess变量,

    public class Job : IJob
       {
           private static ConcurrentDictionary<int, bool> _JobProcess;

    在执行长时间任务前,初始化进度变量

    public void Execute()
            {
                if (_JobProcess == null || _JobProcess.Count== 0||_JobProcess.Count>0)
                {
                    _JobProcess = new ConcurrentDictionary<int, bool>();
                    for (int i = 1; i <= _Step; i++)
                    {
                        _JobProcess.TryAdd(i, false);
                    }
                }

    _Step是步长,这里有简化处理。实际操作中,要对任务进行分类处理,以达到分步的目的。比如,核算客户往来帐目,就以客户为依据来分步长,有121个客户,这里_Step就是121,然后每处理完一个客户的帐目,就把它设置为已经处理,即这样来调用

    for (int i = 1; i <= _Step; i++)
               {
                   _JobProcess[i] = true;
                   Thread.Sleep(2000);
               }

    每处理一个任务,就把它的时度标志为true,以表示已经处理。这样,在进度反馈接口中,可以及时反馈结果

    public object[] GetExecuteStatus()
            {

                  //已经处理完成

                  int completedCount = (from item in _JobProcess
                                                       where item.Value == true
                                                       select item).Count();

                   //当前总任务数量
                    int totalCount = (from item in _JobProcess                                
                                      select item).Count();

                    //正在处理的任务

                    int itemInProcess = (from item in _JobProcess
                                            where item.Value == false
                                            orderby item.Key
                                            select item.Key).FirstOrDefault();

                     }

    将这三个值返回到界面的timer的Tick事件中,实时改变界面的ProgressBar的状态,以达到报告进度的目的。

    当完成功能需要一定的时间,一般定为超过20second,都应该用BackgroundWorker来处理,以保持界面及时响应。

    2 不需要界面发生互动,后台运行完成后,显示结果即可,应用WorkerThreadBase模式

    这个模式最主要的实现类是WorkerThreadBase,

    public abstract class WorkerThreadBase : IDisposable
        {
            private Thread _workerThread;
            private ManualResetEvent _stopping;
            private ManualResetEvent _stopped;
            private bool _disposed;
            private bool _disposing;

    使用了ManualResetEvent来同步多个线程,MSDN中对ManualResetEvent的解释是:通知一个或多个正在等待的线程已发生事件. 如果不能明白它的意思,就跑一下测试代码,来看看用途

    DummyWorker dummyWorker = new DummyWorker();
    dummyWorker.Start();

    CopyFileWorker copyFileWorker = new CopyFileWorker(_copyInfo);
    copyFileWorker.Start();

    //wait for the two threads to finish
    WorkerThreadBase.WaitAll(copyFileWorker, dummyWorker);

    如代码所示,创建2个工作线程,工作线程的创建方法如下

    public class DummyWorker:WorkerThreadBase
        {
            protected override void Work()
            {

             }

    }

    继承于WorkerThreadBase类型,重写Work方法即可。

    当调用WorkerThreadBase.WaitAll停止当前线程,等待所有的线程运行完毕后,然后可以显示结果。


    总结,后一种模式,编程简单,效率也高一些;在WinForm应用中,也常常在Forms类型的方法中,动态创建BackgroundWorker然后调用它,以保持UI继续接受用户输入。

    请到epn.codeplex.com中下载源代码。

  • 相关阅读:
    详解并发和并行意义
    MoleHill Getting Started AGAL(转)
    解决setInterval计时器不准的问题
    Flash视频播放器开发经验总结
    利用pushState开发无刷页面切换
    用小乐图客抓取人人网照片
    如何在Flash中新窗口打开页面而不被拦截
    响应式开发总结
    用Asroute解决复杂状态切换问题
    对iframe跨域通信的封装
  • 原文地址:https://www.cnblogs.com/JamesLi2015/p/2140134.html
Copyright © 2011-2022 走看看