设计目的:
在多线程环境中,多线程处理数据时,如果每线程都单独写数据库,性能低下。因此,为提高性能,数据需批量写到数据库中。出于此目的,进行了数据队列的设计:
实现代码:
1 /// <summary> 2 /// 多线程异步推送数据,一线程异步批量处理数据 3 /// </summary> 4 /// <typeparam name="T"></typeparam> 5 public abstract class SingleThreadQueue<T> 6 { 7 protected List<T> queue; 8 private Action _beforAction;//在批量执行前执行的方法 9 private Action _afterAction;//在批量执行完成后执行的方法 10 private bool _runing = false; 11 private int _maxCount, _maxSize; 12 13 /// <summary> 14 /// 15 /// </summary> 16 /// <param name="maxCount">每次最大处理数</param> 17 /// <param name="maxSize">缓冲最大数</param> 18 /// <param name="beforAction">开始执行处理前的动作</param> 19 /// <param name="afterAction">所有数据处理完成后的动作</param> 20 public SingleThreadQueue(int maxCount, int maxSize, Action beforAction = null, Action afterAction = null) 21 { 22 this.queue = new List<T>(); 23 this._beforAction = beforAction; 24 this._afterAction = afterAction; 25 this._maxCount = maxCount; 26 this._maxSize = maxSize; 27 } 28 29 /// <summary> 30 /// 异步推送数据 31 /// </summary> 32 /// <param name="item"></param> 33 /// <returns>数据成功加入待处理队列,返回true,数据达到队列的最大缓冲,数据不会进入队列,返回false</returns> 34 public bool AsyncEnqueue(T item) 35 { 36 lock (this) 37 { 38 if (this.queue.Count >= this._maxSize) 39 return false; 40 41 this.queue.Add(item); 42 this.Activate(); 43 return true; 44 } 45 } 46 47 protected T[] DoDequeue(List<T> queue) 48 { 49 if (queue.Count > this._maxCount) 50 { 51 var ds = queue.Take(this._maxCount).ToArray(); 52 queue.RemoveRange(0, this._maxCount); 53 return ds; 54 } 55 else 56 { 57 var ds = queue.ToArray(); 58 queue.Clear(); 59 return ds; 60 } 61 } 62 63 /// <summary> 64 /// 实现此方法,批量执行处理时的方法 65 /// </summary> 66 /// <param name="items"></param> 67 protected abstract void OnExecute(T[] items); 68 69 private void Activate() 70 { 71 if (this._runing) 72 { 73 return; 74 } 75 76 this._runing = true; 77 ThreadPool.QueueUserWorkItem((obj) => 78 { 79 try 80 { 81 this._beforAction?.Invoke(); 82 83 T[] items; 84 //管理线程 85 while (true) 86 { 87 lock (this) 88 { 89 if (queue.Count < 1) 90 { 91 this._afterAction?.Invoke(); 92 this._runing = false; 93 break; 94 } 95 96 items = this.DoDequeue(queue); 97 } 98 99 try 100 { 101 this.OnExecute(items); 102 } 103 catch (Exception ex) 104 { 105 //TODO:异常预警 106 // Loger.Exception(ex.Message, ex); 107 } 108 } 109 } 110 catch (Exception ex) 111 { 112 //TODO:异常预警 113 // Loger.Exception(ex.Message, ex); 114 } 115 }); 116 } 117 118 }
经测试,多线程单独写入DB,在开发环境,100/秒,但批量处理可达5000/秒。