zoukankan      html  css  js  c++  java
  • 如何简易的提高吞吐量

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

        因为硬件配置是固定的,那我们只是简单说一说在使用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,或者自行编写的缓存来作为中间件,然后再讲具体入库的操作,放入之前编写好的队列处理里面。

        

    本人对代码不做任何知识产权限制,也不保证所有的代码皆为原创。
  • 相关阅读:
    JIRA4.1 主要功能
    linux之间的远程复制文件
    我在做测试 1
    JOGL简介与安装
    Eclipse RCP中的IAdaptable是什么?
    如何实现关系表的级联删除(ON DELETE CASCADE的用法)
    ubuntu 安装mysql+apache+php
    ubuntu10.10安装VMWare tools
    Struts2 Unable to load configuration. bean 错误解决
    MySQL Workbench “Error Code: 1175” 的解决方法
  • 原文地址:https://www.cnblogs.com/selfteam/p/4912602.html
Copyright © 2011-2022 走看看