• .NET:可扩展的单据编号生成器 之 基于缓冲区的顺序号


    背景

    我在上篇文章“.NET:可扩展的单据编号生成器 之 顺序号(防止重复)”中介绍了如何使用“种子表”和“悲观锁”解决顺序号的问题。昨天找朋友讨论,说这种速度不够高,今天就稍微改进一下,引入一个内存缓冲区,提高生成的速度。

    思路

    引入内存缓冲区后,顺序号的生产流程变为:在内存中维护一个顺序号区间,在这个区间内,就直接查内存,否则更新种子表并重新更新内存区间。还是直接看代码吧。

    实现

    代码下载:http://yunpan.cn/Q5jj5yedRAtk5

    SeedCodeRuleProvider.cs

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Linq;
      4 using System.Text;
      5 using System.Threading.Tasks;
      6 
      7 using System.Transactions;
      8 using System.Text.RegularExpressions;
      9 using System.Data.Entity.Infrastructure;
     10 
     11 namespace EntityCodeRuleDemo
     12 {
     13     public class SeedCodeRuleProvider : ICodeRuleProvider
     14     {
     15         private static readonly int _OnceBufferSize = 10000;
     16         private static readonly Dictionary<string, BufferSeed> _Buffer = new Dictionary<string, BufferSeed>();
     17 
     18         private readonly int _width;
     19 
     20         public SeedCodeRuleProvider(int width)
     21         {
     22             _width = width;
     23         }
     24 
     25         public string Generate(object entity)
     26         {
     27             return GetSeedValue(entity).ToString().PadLeft(_width, '0');
     28         }
     29 
     30         protected virtual string GetKey(object entity)
     31         {
     32             return entity.GetType().FullName;
     33         }
     34 
     35         private int GetSeedValue(object entity)
     36         {
     37             var key = this.GetKey(entity);
     38 
     39             lock (_Buffer)
     40             {
     41                 if (!_Buffer.ContainsKey(key))
     42                 {
     43                     this.SetBufferSeed(entity, key);
     44                 }
     45             }
     46 
     47             lock (_Buffer[key])
     48             {
     49                 if (_Buffer[key].IsOverflow())
     50                 {
     51                     this.SetBufferSeed(entity, key);
     52                 }
     53 
     54                 _Buffer[key].CurrentValue++;
     55 
     56                 return _Buffer[key].CurrentValue;
     57             }
     58         }
     59 
     60         private void SetBufferSeed(object entity, string key)
     61         {
     62             var value = this.GetOrSetSeedValueFormDatabase(entity);
     63 
     64             _Buffer[key] = new BufferSeed
     65             {
     66                 CurrentValue = value - _OnceBufferSize,
     67                 MaxValue = value
     68             };
     69         }
     70 
     71         private int GetOrSetSeedValueFormDatabase(object entity)
     72         {
     73             var key = this.GetKey(entity);
     74 
     75             try
     76             {
     77                 using (var ts = new TransactionScope(TransactionScopeOption.RequiresNew,
     78                     new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead }))
     79                 {
     80                     var value = 0;
     81 
     82                     using (var context = new TestContext())
     83                     {
     84                         var seed = context.CodeSeeds.Where(x => x.Key == key).FirstOrDefault();
     85                         if (seed == null)
     86                         {
     87                             seed = new CodeSeed { Id = Guid.NewGuid(), Key = key, Value = -1 };
     88                             context.CodeSeeds.Add(seed);
     89                         }
     90 
     91                         seed.Value += _OnceBufferSize;
     92                         context.SaveChanges();
     93 
     94                         value = seed.Value;
     95                     }
     96 
     97                     ts.Complete();
     98 
     99                     return value;
    100                 }
    101             }
    102             catch (DbUpdateException)
    103             {
    104                 return this.GetSeedValue(entity);
    105             }
    106         }
    107 
    108         public static SeedCodeRuleProvider SeedCodeRuleProviderFactory(string literal)
    109         {
    110             var match = new Regex("^<种子(:(?<宽度>.*?))?>$").Match(literal);
    111 
    112             var width = match.Groups["宽度"].Value;
    113 
    114             return new SeedCodeRuleProvider(string.IsNullOrEmpty(width) ? 5 : int.Parse(width));
    115         }
    116 
    117         private class BufferSeed
    118         {
    119             public int CurrentValue { get; set; }
    120 
    121             public int MaxValue { get; set; }
    122 
    123             public bool IsOverflow()
    124             {
    125                 return this.CurrentValue >= this.MaxValue;
    126             }
    127         }
    128     }
    129 }

    Program.cs

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 using System.Diagnostics;
     8 using System.Text.RegularExpressions;
     9 
    10 namespace EntityCodeRuleDemo
    11 {
    12     class Program
    13     {
    14         static void Main(string[] args)
    15         {
    16             CodeRuleInterpreter.RegistProviderFactory(new Regex("^<种子(:(?<宽度>.*?))?>$"), SeedCodeRuleProvider.SeedCodeRuleProviderFactory);
    17 
    18             var generator = CodeRuleInterpreter
    19                 .Interpret("前缀_<日期:yyyy_MM_dd>_<属性:NamePinYin>_<种子:6>");
    20 
    21             var watch = Stopwatch.StartNew();
    22 
    23             for (var i = 0; i < 10000; i++)
    24             {
    25                 generator.Generate(new Employee { NamePinYin = "DUANGW" });
    26             }
    27 
    28             watch.Stop();
    29 
    30             Console.WriteLine("1万条编号用时:" + watch.Elapsed);
    31         }
    32     }
    33 }

    执行结果

    备注

     优化前后,速度相差几百倍。

  • 相关阅读:
    【转载】 K2 blackpearl 中的业务规则(Rules)
    【转载】工作流模式与K2实现(2)
    7.10学习内容。 J
    第三章 J
    C博客作业01分支、顺序结构
    C语言博客作业循环结构
    我的C语言第一篇博客!
    使用NDK创建及配置C++程序(原生纯C++项目,不包含JAVA代码)
    关于工作中的错误
    【博文翻译】Building Boost with NDK R5
  • 原文地址:https://www.cnblogs.com/happyframework/p/3077095.html
Copyright © 2020-2023  润新知