zoukankan      html  css  js  c++  java
  • 基于ThreadPool的简单工作管理器

      有这样的场景,淘宝开放平台上有销售订单API,销售订单金额API,商品上下架API,退款API等各种开放的 API,稍微有点规模的商家都会自己开发基于淘宝平台的信息管理系统,里面会涉及到订单管理,采购管理,库存管理,售后管理等,这些管理系统里面的数据都是通过API获取,或者通过API推送到淘宝平台上,这些系统的好处就是避免工作人员直接在淘宝后台进行各项操作。

      基于上面的情况,那么自然会有很多后台程序来跑这些 API,刚开始我是这样设计的。

      

    在一个后台程序里面开几个线程,每个线程对应几个API,这样也能够满足日常需求,但是随着业务量增大,会有各种数据或者任务需要处理,这个时候上面的程序也能满足需求,但是每次都要修改程序,然后在发布,实在是有些头疼。后来我就想,能不能开发一个管理平台,来自动管理这些任务,什么时候想停止任务,直接在配置管理网站上点一下按钮,想开启也是一样操作,如果推出这样的一个管理平台,那么像管理这种业务数据的活可以直接丢给店铺管理人员。

      经过一番思考,想到了这样一种方案,先看图。

      

    上面的图可以很清晰看出工作管理模型。其实到这个时候,最最关心还是工作管理器的内核到底是怎样设计的?那我就说说我的思路是怎样的。

      首先是工作任务运行时间的设计,因为有的API是需要白天运行的有的是晚上闲时运行的,有的是7*24小时不间断运行的,那么我们可以设计这样的一个枚举,命名WorkType,具体内容是:

     public enum WorkType
     {
            ALLWork = 1,
    
            WorkTime = 2,
    
            Morning = 3,
    
            Night = 4
     }

    ALLWork 的运行时间是全天,WorkTime的运行时间是早上9点到晚上22点,Morning的运行时间是凌晨3点到早上9点,Night的运行时间是晚上22点到凌晨3点,相信这几个时间区域很多开发同事都会涉及到的。

      然后是工作线程类WorkThread,将它定义为一个抽象类,里面含有一个抽象方法WorkRun,每一个详细的任务类都会继承WorkThread类,实现抽象方法,也就是说,每个任务的业务处理逻辑都是在WorkRun方法里面实现的。因为上面提到了任务的运行时间区间,那么我们在初始化一个继承WorkThread类的时候,会设置它的运行时间区间。然后在这个抽象类中还还有一个方法,它的作用就是将实现了WorkThread的类丢到ThreadPool里面,看看具体的实现代码。

    public abstract class WorkThread
     {
            private int index;
    
            public WorkThread(int Step,WorkType worktype)
            {
                this.WorkType = worktype;
                this.Step = Step;
                this.index = Step;
            }
    
            public int Step { get;  set; }
    
            public WorkType WorkType { get;  set; }
    
            public bool HasWork
            {
                get
                {
                    bool result = false;
                    switch (WorkType)
                    {
                        case WorkType.Morning:
                            result = index == Step &&  3<=DateTime.Now.Hour && DateTime.Now.Hour<=9 ? true : false;
                            break;
                        case WorkType.WorkTime:
                            result = index == Step && 9 <= DateTime.Now.Hour && DateTime.Now.Hour <= 22 ? true : false;
                            break;
                        case WorkType.Night:
                            result = index == Step && 22 <= DateTime.Now.Hour && DateTime.Now.Hour <= 3 ? true : false;
                            break;
    
                        case WorkType.ALLWork:
                        default:
                            result = index == Step  ? true : false;
                            break;
    
                    }
                    return result;
                }
            }
    
            public abstract void WorkRun(object ob);
           
            public void Run()
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(WorkRun));
                index = 0;
            }
    
            public void AddStep()
            {
                index += 1;
            }
     }

      那么具体的任务类如下。

     public class TestA : WorkThread
     {
            public TestA(int step, WorkType type)
                : base(step, type)
            { }
    
            public override void WorkRun(object ob)
            {
                Console.WriteLine(string.Format("我是A小姐,我开始工作了。时间:{0}", DateTime.Now));
            }
     }

      其实到这里了,有的人会想到,那我们怎么来管理这些WorkThread类了,这里我们专门有一个类来管理WorkThread,这里命名为WorkManager。这个类里面的结构就相当简单了。看到上面的模型图,可以猜出一些端倪。里面专门定义了一个字典项,用来存储每一个WorkThread,它是ConcurrentDictionary,表示可由多个线程同时访问的键值对的线程安全集合。管理类里面还定义了4个方法,增加删除WorkThread,开始结束WorkThread。具体看下面的代码。

    public class WorkManager
    {
            static readonly ConcurrentDictionary<string, WorkThread> WorkCache = 
                new ConcurrentDictionary<string, WorkThread>();
    
            public int WorkCount 
            {
                get { return WorkCache.Count; }
            }
    
            public void AddWork(WorkThread workThread)
            {
                WorkCache.TryAdd(workThread.GetType().FullName, workThread);
            }
    
            public void RemoveWork(string workThreadId)
            {
                var obj = WorkCache[workThreadId];
                if(obj != null)
                    WorkCache.TryRemove(workThreadId, out obj);
            }
    
            public void StartWork()
            {
                Action action = () =>
                {
                    while (true)
                    {
                        foreach (KeyValuePair<string, WorkThread> work in WorkCache)
                        {
                            if (work.Value.HasWork)
                            {
                                work.Value.Run();
                            }
                            else
                            {
                                work.Value.AddStep();
                            }
                        }
    
                        Thread.Sleep(5000);
                    }
                };
                action.BeginInvoke(cb => action.EndInvoke(cb), null);
            }
    
            public void EndWork()
            {
                Action action = () =>
                {
                    WorkCache.Clear();
                };
                action.BeginInvoke(cb => action.EndInvoke(cb), null);
            }
    
    }

    代码是不是很简单,到这里位置,工作管理的内核代码全部上完了,那我们该怎么调用了,看看下面调用代码。

                Console.Title = "工作管理器";
    
                WorkManager manager = new WorkManager();
                manager.AddWork(new TestA(1, WorkType.ALLWork));
                manager.AddWork(new TestB(1, WorkType.ALLWork));
                manager.StartWork();
    
                Console.WriteLine("1.全部开始工作");
                Thread.Sleep(15 * 1000);
    
                manager.EndWork();
                Console.WriteLine("2.全部卸载");
    
                Thread.Sleep(10 * 1000);
                manager.AddWork(new TestB(1, WorkType.ALLWork));
                Console.WriteLine("3.加入B");
    
                Console.Read();    

    看一下运行效果图:

      大家看完之后是不是觉得很简单,不过有什么疑问可以在这里留言,谢谢。

      示例代码下载:https://files.cnblogs.com/wucj/WorkManager.rar

  • 相关阅读:
    移动端底部fixed固定定位输入框ios下不兼容
    mint-ui Picker设置指定初始值
    vue项目的mode:history模式
    更改checkbox的默认样式
    vue组件通信的几种方式
    Python运行Google App Engineer时出现的UnicodeDecodeError错误解决方案
    ActionFilterAttribute之HtmlFilter,压缩HTML代码
    MongoDB C#驱动中Query几个方法
    无需路由端口映射 花生壳6.5工程版发布
    如何让搜索引擎抓取AJAX内容?
  • 原文地址:https://www.cnblogs.com/wucj/p/2440335.html
Copyright © 2011-2022 走看看