好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

.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  }

执行结果

备注

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

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于.NET:可扩展的单据编号生成器 之 基于缓冲区的顺序号的详细内容...

  阅读:42次