首页 > 学院 > 开发设计 > 正文

如何简易的提高吞吐量

2019-11-14 13:51:11
字体:
来源:转载
供稿:网友

    性能提升还是那几个要素,就像我在之前的博文里面提到的一样,这一篇只是更加简单一点而已。

    因为硬件配置是固定的,那我们只是简单说一说在使用C#进行开发的项目中,如何使用一些简单的小招数让性能有一个比较大幅度的显著提升。

    一、绕开那些烦人却又不可避免的DB操作。

    DB操作是不可避免却又是项目重中之中的所在,那我们可以做哪些优化呢?

    首先,根据业务将DB操作分为需要即时和非即时的两块,关于非即时的我们可以将其单独的交给某一个线程来单独慢慢处理。代码如下:

public class DbActionQueue : IDisposable    {        public Queue<Action> _transQueue;        PRivate Thread _thread;        private bool _isDispose = false;        private static readonly object _syncObject = new object();        private readonly object _syncQueueObject = new object();        private static DbActionQueue _instance;        public static DbActionQueue Instance        {            get            {                if (_instance == null)                {                    lock (_syncObject)                    {                        if (_instance == null)                        {                            _instance = new DbActionQueue();                        }                    }                }                return _instance;            }        }        private DbActionQueue()        {            if (_transQueue == null)            {                _transQueue = new Queue<Action>();            }            if (_thread == null)            {                _thread = new Thread(Thread_Work)                {                    IsBackground = true                };            }            _thread.Start();        }        public void Push(Action action)        {            if (_transQueue == null) throw new ArgumentNullException("dbActionQueue is not init");            lock (_syncQueueObject)            {                _transQueue.Enqueue(action);            }        }        public void Thread_Work()        {            while (!_isDispose)            {                Action[] items = null;                if (_transQueue != null && _transQueue.Count > 0)                {                    lock (_syncQueueObject)                    {                        items = new Action[_transQueue.Count];                        _transQueue.CopyTo(items, 0);                        _transQueue.Clear();                    }                }                if (items != null && items.Length > 0)                {                    foreach (var item in items)                    {                        try                        {                            item.Invoke();                        }                        catch (Exception ex)                        {                            LogHelper.Write(string.Format("DbActionQueue error. | Exception.StackTrace:{0}", ex.StackTrace), ex);                        }                    }                }                Thread.Sleep(1);            }        }        public void Dispose()        {            _isDispose = true;            _thread.Join();        }    }
View Code

    通过代码可以看到,我们在实例化的时候,单独创建了一个线程,用来做处理。

    那对于一些像日志之类的操作,则可以通过以下代码进行操作:

DbActionQueue.Instance.Push(() =>{    LogBLL.Instance.Add(new Log                        {                            action_time = DateTime.Now;                        });});            
View Code

    到这里不难免要问了,如果数据量过大,单个队列已经无法满足的时候,怎么做处理。关于队列的监控,优化不在该文讨论,通俗一点的做法可以引入一些第三方的队列。另外在项目中,其实我们更多的时候,实际上并不是在Insert,Update,Delete等操作,而是Select的操作,那关于Select的一些缓存处理,也不在该文的讨论范畴,因为关于Cache的各种中间件实在太多,而且篇幅太大。

    可能在某些时候,我们还是觉得单个线程处理太慢,希望多开几个线程来处理对于DB的请求,则我们可以根据实际业务情况和机器配置,初始化任意个线程来处理,则以上代码需要稍稍改装一下,将单例的换成可自由实例化的,代码如下:

 public class DbQueue    {        public Queue<Action> _transQueue;        private Thread _thread;        private bool _isDispose = false;        private readonly object _syncQueueObject = new object();        public DbQueue()        {            if (_transQueue == null)            {                _transQueue = new Queue<Action>();            }            if (_thread == null)            {                _thread = new Thread(Thread_Work)                {                    IsBackground = true                };            }            _thread.Start();        }        public void Thread_Work()        {            while (!_isDispose)            {                Action[] items = null;                if (_transQueue != null && _transQueue.Count > 0)                {                    lock (_syncQueueObject)                    {                        items = new Action[_transQueue.Count];                        _transQueue.CopyTo(items, 0);                        _transQueue.Clear();                    }                }                if (items != null && items.Length > 0)                {                    foreach (var item in items)                    {                        try                        {                            item.Invoke();                        }                        catch (Exception ex)                        {                            LogHelper.Write(string.Format("DbActionQueue error. | Exception.StackTrace:{0}", ex.StackTrace), ex);                        }                    }                }                Thread.Sleep(1);            }        }        public void Push(Action action)        {            if (_transQueue == null) throw new ArgumentNullException("dbActionQueue is not init");            lock (_syncQueueObject)            {                _transQueue.Enqueue(action);            }        }        public void Dispose()        {            _isDispose = true;            _thread.Join();        }    }
View Code

 那多个线程之间的处理,代码则如下:

 public class DbQueueManage    {         private int _threadNumber = 2;        private DbQueue[] _dbQueues;        private Random random = new Random();        private DbQueueManage()        {                    }        static DbQueueManage()        {        }        private static readonly object _syncObject = new object();        private static DbQueueManage _instance;        public static DbQueueManage Instance        {            get            {                if (_instance == null)                {                    lock (_syncObject)                    {                        if (_instance == null)                        {                            _instance = new DbQueueManage();                        }                    }                }                return _instance;            }        }        public void Init(Action action, int threadNum = 2)        {            if (_dbQueues == null)            {                this._threadNumber = threadNum;                _dbQueues = new DbQueue[threadNum];                for (var i = 0; i < threadNum; i++)                {                    _dbQueues[i] = new DbQueue();                }            }        }        public void Push(Action action)        {            var index = GetRandomThreadIndex();            if (_dbQueues != null && _dbQueues.Length > index)            {                _dbQueues[index].Push(action);            }        }        public int GetRandomThreadIndex()        {            return random.Next(0, this._threadNumber);        }    }
View Code

另外关于为什么不选用Task来做处理,虽然Task关于线程的处理还是很优秀的,这里请各位同僚自行定夺。关于即时性的DB操作,则可以以Redis,MongoDb,或者自行编写的缓存来作为中间件,然后再讲具体入库的操作,放入之前编写好的队列处理里面。

    


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表