• 自动化控制之重码校验


    看到公司项目里每次都写生产流程都是需要一个环节,那就是重码校验。和同事交流有怀疑Queue的性能的,主要是担心队列元素过多效率低。需求:实现一个先进先出FIFO的队列,在每次生产前去本地数据库看看之前生产的批次有没有采集过,如果有则需要读取到队列里。生产中校验某个码,如果校验不重复则加入队列。校验通不过则需要剔除。目前产线的采集器(工业相机)是随产品在流水线各个工位依次触发的。暂时不存在多个线程并发访问FIFO队列的情况,所以即使使用普通的Queue也是正常不出问题的。现在封装了一下,用上了线程安全版本的ConcurrentQueue。

    /// <summary>
        /// 重码校验队列
        /// </summary>  
        public class RepeatCheckQueue
        {
            protected ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
            private volatile int barcodeCount = 100;
            /// <summary>
            /// 队列长度,默认100
            /// </summary>
            public int BarcodeCount
            {
                get
                {
                    return queue.Count;
                }
            }
            /// <summary>
            /// 构造函数,需要传值指明队列长度
            /// </summary>
            /// <param name="count">队列长度</param>
            public RepeatCheckQueue(int count)
            {
                barcodeCount = count;
                //加载已有码的委托声明
                LoadItemFromDB = (list) =>
                {
                    if (list.Count > barcodeCount)
                        throw new Exception("队列长度超限!");
                    foreach (Barcode code in list)
                        queue.Enqueue(code.Code);
                };
                //校验重码的委托声明
                CheckIsRepeat = (t, isAddtoQueue) =>
                {
                    bool result = false;
                    result = queue.Contains(t);
                    //不存在且需要加入则自动加入队列
                    if (!result && isAddtoQueue)
                    {                    
                        queue.Enqueue(t);
                        if (queue.Count > barcodeCount)
                        {
                            string code;
                            queue.TryDequeue(out code);
                        }
                    }
                    return result;
                };
            }
            /// <summary>
            /// 从数据库加载已有数据
            /// </summary>
            public Action<List<Barcode>> LoadItemFromDB;
            /// <summary>
            /// 检查条码是否重复,并确定是否加入队列
            /// </summary>
            public Func<string, bool, bool> CheckIsRepeat;
    
            public string GetQueueCode()
            {
                return queue.FirstOrDefault().ToString();
            }
        }
    

    测试用例:

     Stopwatch sw = new Stopwatch();
                List<Barcode> list = new List<Barcode>();
                Func<RepeatCheckQueue> initQueue = () =>
                {
                    sw.Start();
                    list = LoadFromXML<Barcode>("100w_guid.xml");
                    Console.WriteLine(DateTime.Now +"->"+string.Format("{0}个码已经加载到内存!", list.Count));
                    var repeatCheckQueue = new RepeatCheckQueue(list.Count);
                    repeatCheckQueue.LoadItemFromDB(list);
                    return repeatCheckQueue;
                };
                initQueue.BeginInvoke((result) =>
                {
                    RepeatCheckQueue checker = initQueue.EndInvoke(result);
                    sw.Stop();
                    Console.WriteLine(DateTime.Now + "->" + string.Format("{0}个码已经加载到队列!", checker.BarcodeCount));
                    Console.WriteLine(DateTime.Now + "->" + string.Format("准备队列耗时:{0} !", sw.ElapsedMilliseconds.ToString()));
                    //生成一个测试的随机码
                    string check_first = string.Join("", Guid.NewGuid().ToByteArray());
                    var result_Check = checker.CheckIsRepeat(check_first, true);
                    Console.WriteLine(DateTime.Now + "->" + string.Format("校验的第一个码:{0},", check_first) + result_Check);
                    Console.WriteLine(result_Check);
                    Console.WriteLine(checker.BarcodeCount);
                    Console.WriteLine(DateTime.Now + "->" + string.Format("当前队列的第一个码:{0},", checker.GetQueueCode()) + result_Check);
                    Console.WriteLine("******************************");
                    //第二个码
                    string code_first = list.Skip(0).Take(1).FirstOrDefault().Code;
                    result_Check = checker.CheckIsRepeat(code_first, true);
                    Console.WriteLine(string.Format(DateTime.Now + "->" + "文件里第2码:{0},", code_first) + result_Check);
                    //第三个
                    string code_second = list.Skip(2).Take(1).FirstOrDefault().Code;
                    result_Check = checker.CheckIsRepeat(code_second, true);
                    Console.WriteLine(string.Format(DateTime.Now + "->" + "文件里第3码:{0},", code_second) + result_Check);
                    Console.WriteLine(checker.BarcodeCount);
                    Console.WriteLine("************并行测试************");
                    Random rd = new Random();
                    //随机取队列里的一个码来校验
                    Action action = () =>
                    {
                        for (int i = 0; i < 3; i++)
                        {
                            int index = rd.Next(list.Count);
                            string code = list.Skip(index).Take(1).FirstOrDefault().Code;
                            result_Check = checker.CheckIsRepeat(code, true);
                            Console.WriteLine(DateTime.Now + "->" + code + "," + result_Check);
                            Console.WriteLine(checker.BarcodeCount);
                        }
                    };
                    Parallel.Invoke(action, action, action, action, action, action, action, action);
                }, null);
                Console.WriteLine("正在初始化重码队列...");
                Console.ReadKey();
    

    测试结果:队列里放入100万个码,使用从xml读取100万,然后一个入队的方式,耗时3秒不到,ConcurrentQueue的好处就是支持多线程分批次和并行入队出队。不需要lock,没毛病,一个字:快。

  • 相关阅读:
    SecureCRT_FX8.0完整版
    bridge
    Quartz 框架 教程(中文版)2.2.x
    Quartz教程五:SimpleTrigger
    Quartz教程四:Trigger
    Quartz教程三:Job与JobDetail介绍
    Quartz教程二:API,Job和Trigger
    Quartz教程一:使用quartz
    Quartz教程:快速入门
    Kubernetes 1.5.3 部署
  • 原文地址:https://www.cnblogs.com/datacool/p/datacool_RepeatCheck.html
Copyright © 2020-2023  润新知