自动化控制之重码校验

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/// <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();
        }
    }

测试用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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,没毛病,一个字:快。

posted @   数据酷软件  阅读(510)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示