.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://HdhCmsTestcnblogs测试数据/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于.NET:可扩展的单据编号生成器 之 基于缓冲区的顺序号的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did45735