.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:可扩展的单据编号生成器 之 基于缓冲区的顺序号的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did45735