分享

解决CPU严重消耗的问题

 X的世界 2013-01-09
CPU us 高的解决办法
原因:通常CPU us高的原因是由用户线程一直在无阻塞的进行计算等,造成其他线程饿死的情况,针对这一情况,我们可以让该计算型线程间歇性的执行,即在代码的执行过程中添加Thread.Sleep();来释放CPU的执行权,从而让其他的线程获得执行。
还有一种场景就是状态的扫描,例如某线程要等到其他线程改变了值之后才可继续执行,对于这种场景可以利用CountDownLatch或者采用wait/notify机制。
CPU sy高的解决办法
原因:线程过多导致的线程的调度,从而由于线程上下文切换导致CPU sy增加。最简单的方法是减少线程数。
 还有一个原因就是线程之间锁竞争激烈所导致的。如何减少锁竞争,解决方法有:
  1、使用java并发包
2、使用treiber算法,这是一个线程安全的无阻塞的Stack。
3、使用Michael-Scott非阻塞队列算法。
(2,3中的两种算法都是基于CAS和AtomicReference来实现的非阻塞算法)
4、尽可能少使用锁
5、减少锁的作用域
6、分段锁--ConcurrentHashMap使用的16段分段锁。但可能造成在做全集操作时(例如size())会增加复杂度。
7、去除读写操作的互斥锁。----将读锁和写锁分开,例如CopyOnWriteArrayList,读取数据时并不占用锁,这可以提高读取的性能,但对于写操作时需要复制整个对象数组,这是一个不足之处。
当不得不用非常多线程的时候,例如数据库连接池等,如何降低CPU sy高的问题,这就应该考虑到使用协程Coroutine。采用协程后,可以让某个线程内的任务在等待某个操作阻塞时,就立即释放该任务所在线程内所占的资源给其他任务使用,当阻塞被唤醒时重新执行原任务。
各种语言在实现Coroutine方式的支持时,多数都采用了Actor Model来实现,Actor Model简单来说就是每个任务就是一个ActorActor之间通过消息传递的方式来进行交互,而不采用共享的方式,Actor可以看做是一个轻量级的进程或线程,通常在一台4G内存的机器上,创建几十万个Actor是毫无问题的,Actor支持Continuations,即对于如下代码:

         Actor

                   act方法

                            进行一些处理

创建并执行另外一个Actor(此时放弃控制使得另一个Actor从这个Actor停止的地方开始 )                          

       通过消息box阻塞获取另一个Actor执行的结果

                            继续基于这个结果进行一些处理

         在支持Continuations的情况下,可以做到消息box阻塞时并不是进程或线程级的阻塞,而只是Actor本身的阻塞,并且在阻塞时可将所占据的进程或线程释放给其他Actor使用,Actor Model实现最典型的就是erLang了。

         对于Java应用而言,传统方式下为了支持高并发,由于一个线程只能用于处理一个请求,即使是线程中其实有很多IO中断、锁等待也同样如此,因此通常的做法是通过启动很多的线程来支撑高并发,但当线程过多时,就造成了CPU需要消耗不少的时间在线程的切换上,从而出现瓶颈,按照上面对Coroutine的描述,Coroutine的方式理论上而言能够大幅度的提升Java应用所能支撑的并发量。

协程与子例程之间的对比

子例程的起始处是惟一的入口点,一旦退出即完成了子程序的执行,子程序的一个实例只会返回一次。

协程可以通过yield来调用其它协程。通过yield方式转移执行权的协程之间不是调用者与被调用者的关系,而是彼此对称、平等的。

协程的起始处是第一个入口点,在协程里,返回点之后是接下来的入口点。子例程的生命期遵循后进先出(最后一个被调用的子例程最先返回);相反,协程的生命期完全由他们的使用的需要决定。

这里是一个简单的例子证明协程的实用性。假设你有一个生产者-消费者的关系,这里一个协程生产产品并将它们加入队列,另一个协程从队列中取出产品并使用它。为了提高效率,你想一次增加或删除多个产品。代码可能是这样的:

var q := new queue

生产者协程

   loop
       while q is not full
           create some new items
           add the items to q
       yield to consume

消费者协程

   loop
       while q is not empty
           remove some items from q
           use the items
       yield to produce

每个协程在用yield命令向另一个协程交出控制时都尽可能做了更多的工作。放弃控制使得另一个例程从这个例程停止的地方开始,但因为现在队列被修改了所以他可以做更多事情。尽管这个例子常用来介绍多线程,实际没有必要用多线程实现这种动态:yield语句可以通过由一个协程向另一个协程直接分支的方式实现。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多