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

執行結果

備注

 優化前后,速度相差幾百倍。

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM