如何简易的提高吞吐量

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

因为硬件配置是固定的,那我们只是简单说一说在使用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();
        }
    }

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

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

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

到这里不难免要问了,如果数据量过大,单个队列已经无法满足的时候,怎么做处理。关于队列的监控,优化不在该文讨论,通俗一点的做法可以引入一些第三方的队列。另外在项目中,其实我们更多的时候,实际上并不是在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();
        }
    }

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

 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);
        }

    }

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

时间: 2024-10-23 05:31:52

如何简易的提高吞吐量的相关文章

简易方法提高手机3G上网速度(2G转3G)

这里提到的方法是将手机信号不好的地方(也就是2G信号)强制转换为3G信号上网以至于提高上网速度,大家经常看到在某个地方(比如坐地铁)手机明明是3G卡,却显示的是2G信号,这就是手机老在2G和3G之间切换,这时我们想着各种办法是提高手机的上网速度,增加手机的上网体验.那么我在这里提到一个方法挺实用的,可以避免上述的尴尬情况!赶紧试试吧! 步骤1.大家可以打开手机的拨号界面,输入:*#*#4636#*#*,就会出现如下界面: 步骤2:点击手机信息,会出现以下的界面: 步骤3:运行"ping测试&qu

服务器优化:提高吞吐量,给主机加油

对于网页服务器的加速方法有很多,例如我们可以采用CDN技术,但是这种提速方案很有局限性,不能真正的全面提高服务器速度.      当然了,对于服务器的提速方案也要根据具体情况而言,比如对于香港服务器,我们应该采用充分提高服务器带宽利用率来达到相应的提速要求,对于一些容易抽风的地区,我们也可以采用此方案.      我们今天主要利用锐速(serverspeeder)软件来提高主机的吞吐量,达到服务器提速的效果,此软件运用起来也是相当的方便. 软件的安装过程      我的实验环境仍是CentOs6

网卡可以绑定cpu提高吞吐量

请看大神帖子:https://blog.csdn.net/nawenqiang/article/details/82854929 需要做什么呢? 首先,确认你是否运行irqbalance,这个是nice守护进程它会自动在cpu间扩展中断.在繁忙的系统中很重要,尤其是两块网卡,因为默认cpu0 将处理所有中断,系统很容易过载.irqbalance扩散这些中断用以降低负载.为了性能最大化,你可以手动平衡这些中断将套接字和超线程共享内核分 散,但是通常没必要这么麻烦. 原文地址:https://www

【Twitter Storm系列】Storm环境配置及吞吐量测试调优--个人理解

1.硬件配置信息 6台服务器,2个CPU,96G,6核,24线程 2.集群信息 Storm集群:1个nimbus,6个supervisor nimbus:192.168.7.127 supervisor: 192.168.7.128 192.168.7.129 192.168.7.130 192.168.7.131 192.168.7.132 192.168.7.133 Zookeeper集群: 3个节点 192.168.7.127:2181, 192.168.7.128:2181, 192.1

SQL Server如何提高数据库备份的速度

对于一个数据库完整备份来说,备份的速度很大程度上取决于下面两个因素:读磁盘数据.日志文件的吞吐量,写磁盘数据文件的吞吐量. 下图是备份过程中磁盘的变化情况: 读吞吐量 读吞吐量的大小取决于磁盘读取数据的速度,而磁盘读取的速度又取决于数据文件在磁盘中的位置.因此,位于不同盘符上不同数据库文件的读取速度都不相同. 测量读吞吐量的一个方法就是进行一次数据库完整备份,然后使用Windows性能监控器(perfmon)来监控数据库文件所在磁盘的Read bytes/sec 性能计数器.保存备份文件的磁盘应

JVM实用参数(六) 吞吐量收集器

JVM实用参数(六) 吞吐量收集器 原文链接 本文连接 译者:张军  校对:梁海舰 在实践中我们发现对于大多数的应用领域,评估一个垃圾收集(GC)算法如何根据如下两个标准: 吞吐量越高算法越好 暂停时间越短算法越好 首先让我们来明确垃圾收集(GC)中的两个术语:吞吐量(throughput)和暂停时间(pause times). JVM在专门的线程(GC threads)中执行GC. 只要GC线程是活动的,它们将与应用程序线程(application threads)争用当前可用CPU的时钟周期

四种途径提高RabbitMQ传输数据的可靠性(二)

前言 上一篇四种途径提高RabbitMQ传输消息数据的可靠性(一)已经介绍了两种方式提高数据可靠性传输的方法,本篇针对上一篇中提出的问题(1)与问题(2)提出解决常用的方法. 本文其实也就是结合以上四个方面进行讲解的,主要参考<RabbitMQ实战指南>(有需要PDF电子书的可以评论或者私信我),本文截图也来自其中,另外可以对一些RabbitMQ的概念的认识可以参考我的另外两篇博文认识RabbitMQ交换机模型.RabbitMQ是如何运转的? 三.生产者确认机制 针对问题(1),我们可以通过生

kafka为什么吞吐量高

1:kafka可以通过多个broker形成集群,来存储大量数据:而且便于横向扩展. 2:kafka信息存储核心的broker,通过partition的segment只关心信息的存储,而生产者只负责向leader角色的partition提交数据,而消费者pull数据的时候自己通过zk存储offset信息,严格讲broker基本只关心存储数据: 3:kafka的ack策略也是提高吞吐量的手段: 1)生产者的acks如果设置0则只向leader发送数据,并不关心leader数据是否存储成功: 2)如果

Spring boot 实现高吞吐量异步处理(适用于高并发场景)

技术要点 org.springframework.web.context.request.async.DeferredResult<T> 示例如下: 1.   新建Maven项目  async 2.   pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaL