关于并发下内存及cpu使用情况的思考

又见阿郎 又见阿郎     2022-10-12     470

关键词:

鉴于昨天的文章<<使用Interlocked在多线程下进行原子操作,无锁无阻塞的实现线程运行状态判断>>里面有一个封装好的无锁的类库可以判断并发下的结束状况,我们可以完成并发时,以及并发的同时做一些事,因此,今天我做了个小demo:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp6
{
    
    public enum CoordinationStatus
    {
        AllDone,
        Timeout,
        Cancel
    };

    public sealed class AsyncCoordinator
    {
        private Int32 m_opCount = 1;        // Decremented when AllBegun calls JustEnded
        private Int32 m_statusReported = 0; // 0=false, 1=true
        private Action<CoordinationStatus> m_callback;
        private Timer m_timer;

        // This method MUST be called BEFORE initiating an operation
        public void AboutToBegin(Int32 opsToAdd = 1)
        {
            Interlocked.Add(ref m_opCount, opsToAdd);
        }

        // This method MUST be called AFTER an operations result has been processed
        public void JustEnded()
        {
            if (Interlocked.Decrement(ref m_opCount) == 0)
                ReportStatus(CoordinationStatus.AllDone);
        }

        // This method MUST be called AFTER initiating ALL operations
        public void AllBegun(Action<CoordinationStatus> callback, Int32 timeout = Timeout.Infinite)
        {
            m_callback = callback;
            // 是否需要永远运行
            if (timeout != Timeout.Infinite)
            {
                // 在指定的时间点(dueTime) 调用回调函数,随后在指定的时间间隔(period)调用回调函数
                m_timer = new Timer(TimeExpired, null, timeout, Timeout.Infinite);
            }
            JustEnded();
        }

        // 处理过时的线程
        private void TimeExpired(Object o)
        {
            ReportStatus(CoordinationStatus.Timeout);
        }

        public void Cancel()
        {
            if (m_callback == null)
                throw new InvalidOperationException("Cancel cannot be called before AllBegun");
            ReportStatus(CoordinationStatus.Cancel);
        }

        private void ReportStatus(CoordinationStatus status)
        {
            if (m_timer != null)
            {  // If timer is still in play, kill it
                Timer timer = Interlocked.Exchange(ref m_timer, null);
                if (timer != null) timer.Dispose();
            }

            // If status has never been reported, report it; else ignore it
            if (Interlocked.Exchange(ref m_statusReported, 1) == 0)
                m_callback(status);
        }
    }

    

    class Program
    {
        static AsyncCoordinator m_ac = new AsyncCoordinator();
        static void Main(string[] args)
        {
            Console.BufferHeight = Int16.MaxValue - 10;
            Console.BufferWidth = Int16.MaxValue - 10;

            ConcurrentQueue<int> concurrentQueue = new ConcurrentQueue<int>();

            for(int i =0;i<10000; i++)
            {
                concurrentQueue.Enqueue(i);
            }

            Console.WriteLine("添加完毕....");

            var t = new Task[50];
            
            for (int i=0; i<50; i++)
            {
                m_ac.AboutToBegin(1);
                t[i] = Task.Factory.StartNew((param) =>
                {
                    while (concurrentQueue.Count>0)
                    {
                        int x;
                        if(concurrentQueue.TryDequeue(out x))
                        {
                            Console.WriteLine(x + "   线程Id: {0},   线程数: {1}", Task.CurrentId, param.ToString());
                        }
                        //Thread.Sleep(150);
                    }
                    m_ac.JustEnded();
                }, i);
            }
            
            m_ac.AllBegun(AllDone, Timeout.Infinite);
            Console.ReadKey();
        }

        public static void AllDone(CoordinationStatus status)
        {
            switch (status)
            {
                case CoordinationStatus.Cancel:
                    Console.WriteLine("Operation canceled.");
                    break;

                case CoordinationStatus.Timeout:
                    Console.WriteLine("Operation timed-out.");
                    break;

                case CoordinationStatus.AllDone:
                    Console.WriteLine("处理完毕....");
                    break;
            }
        }
    }
}

但是发现了一个问题:

这CPU使用率....
然后我看了下输出结果:

可以看到线程数才只有5个(我的线程数是从0开始算的),这不会啊,明明我们就开了50个线程啊,不过不管开多少个线程,这CPU扛不住啊,要是说在项目中的某个模块需要用到并发,这CPU使用率你扛得住?服务器本来配置就不会太好,网站的其余模块不要用CPU了?而且,我明明开了50个线程跑啊,为什么只有五个线程?其实很简单,因此并发下,代码只用了五个线程就跑完了这一万个数据,剩下的线程开了没有用武之地。找到只有五个线程开着的原因了之后,要想想怎么解决啊,多的45个线程也是要占内存的,尽管是线程池线程,但也是要占用内存啊,既然是因为并发下运行太快,只要五个线程就能跑满一万个数据,那我就阻塞一会线程就可以了,这样让剩下的45个线程能够有机会运行。改代码!
将上面的Thread.Sleep(150)的注释给去掉哦!

嗯,这个结果还是可以的,但是有个Console host占用内存高啊,占就占呗,反正该用的内存还是要用。我们睡眠了一段时间的线程,那么与不睡眠相比,并发的CPU使用率是不是下降了?我们开线程最好的期待不就是跑满CPU么?其实不然,开线程不过就是为了更快的运行程序,将耗时的程序分批次运行,但是如果期间占用CPU太高,我这里是个demo,占用CPU时间很短,也就几十秒。但是真的项目中会允许么?具体情况具体分析吧,如果不介意的话,可以这么跑,大不了另外弄个服务器专门跑并发,然后将数据存储到数据库中(如果你的业务是: 并发调用第三方接口,然后将接口获取的数据做处理,完全可以采用这种设计)。但是请注意,还是不要太耗费CPU的好。
并发线程的睡眠时间,我们也可以自己调节下,建议是100-200ms吧。

redis故障排查「连接失败问题排查和解决」带你总体分析cpu及内存的使用率高问题排查指南及方案

...资源越高,这会导致CPU使用率超高,容易触发主备倒换。关于各命令对应的时间复杂度信息请参见Redis官网。例如,使用了keys等消耗资源的命令,导致CPU超高,建议客户改成scan命令或者禁用keys命令。慢查询的定位找出CPU使用率... 查看详情

关于后台部分业务重构的思考及实践

关于后台部分业务重构的思考及实践作者:ljmatlight时间:2017-09-25积极主动,想事谋事,敢作敢为,能做能为。当职以来,随着对公司业务和项目的不断深入,不断梳理业务和公司技术栈。保证在完成分配开发任务情况下,积极... 查看详情

内存在电脑上怎么查看

...方法一、右击【我的电脑】,点击【属性】,就可以看到内存大小。方法二、右击【开始】按钮,点击【搜索】,在搜索框中输入【内存】,点击【显示此计算机RAM大小】,这样就可以看到电脑内存大小了。1/3右键“开始”选择... 查看详情

esxi中不能显示cpu及内存使用情况的解决方法(代码片段)

环境:centos7,内核版本高于3.10解释的话不多说,直接上才艺查看当前内核版本uname–r更新centosyum–yupdate如果安装过旧版本则卸载yumremovedockerdocker-commondocker-selinuxdocker-engine安装依赖的软件包yuminstall-yyum-utilsdevice-mapper-persisten... 查看详情

高并发下的内存管理技巧

  1、为何高并发下容易oom    1)首先我们了解当执行垃圾回收的时候,会导致进程暂停,从而使我们的程序卡死;进程长时间暂停,又会导致大量的请求积压等待处理,垃圾回收刚刚结束,更多的请求立刻涌进来,迅速... 查看详情

redis故障排查「连接失败问题排查和解决」带你总体分析cpu及内存的使用率高问题排查指南及方案(代码片段)

...,这会导致CPU使用率超高,容易触发主备倒换。关于各命令对应的时间复杂度信息请参见Redis官网。例如,使用了keys等消耗资源的命令,导致CPU超高,建议客户改成scan命令或者禁用keys命令。慢查询的定位找出... 查看详情

性能及优化之vmstat

...定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix最喜爱的命令,一个是Linux/Unix都支持,二是相比top,我可以看到整个机器的CPU,内存,IO的使用情况,而... 查看详情

统计cpu使用情况及查看前5名

psaux排序按内存升序排列;psaux--sort=+rss按内存降序排列;psaux--sort=-rss按cpu升序排列;psaux--sort=+%cpu为按cpu降序排列。psaux--sort=-%cpupsaux--sort=+%cpu|head-5 查看详情

linux查看内存使用情况

linux查看内存使用情况的方法是,1,proc。meminfo,查看RAM使用情况最简单的方法是通过,procmeminfo。这个动态更新的虚拟文件实际上是许多其他内存相关工具free,ps,top的组合显示。2,atop。atop命令是一个终端环境的监控命令。... 查看详情

如何从 C# 分析内存和 CPU 使用情况

...得我的进程使用的***内存和CPU。拜托,有人可以给我一个关于如何使用托管代码的指南吗?(我也使用单声道在linux上运行它)。架构如下:进程test.exe启动两个进程:A.exe和B.exe。我需要测量 查看详情

监控cpu磁盘内存使用情况,并报警

#!/bin/bash#获取cpu使用率cpuUsage=`top-n1|awk-F‘[%]+‘‘NR==3{print$2}‘`#获取磁盘使用率data_name="/dev/sda1"diskUsage=`df-h|grep$data_name|awk-F‘[%]+‘‘{print$5}‘`logFile=/apps/service/wy/jiankong.log#获取内存情况mem_tota 查看详情

如何测量 F# 代码的 CPU 和内存使用情况?

...7:26【问题描述】:我是F#语言的新手,目前我正在做一个关于F#性能的简短研究。所以我想做的是对我的F#代码进行基准测试。我已经找到了Stopwatch类,这很明显,但至于你应该能够测试的其余部分,我没有找到明确的线索。我... 查看详情

高并发下的hashmap为什么会死循环

作者| tech-bus.七十一来源| 程序员巴士前言  HashMap并发情况下产生的死循环问题在JDK1.7及之前版本是存在的,JDK1.8通过增加loHead头节点和loTail尾节点进行了修复,虽然进行了修复,但是如果涉及到并发情况下需要... 查看详情

关于在zabbix监测脚本中使用ps命令监控进程cpu使用率和内存使用率,获得数据为0的情况描述(代码片段)

前提:想自己编写zabbix监测脚本,然后通过配置模板的方式,实现对资源(cpu和内存)使用率高的进程进行监控。过程描述:zabbix版本为2.21,被监控主机操作系统为CentOS6.4。脚本中主要命令如下:percent=0;#通过脚本输入参数proces... 查看详情

kubernetescpu管理及调度

参考技术A在内存管理篇,我们研究了Kubernetes(K8s)requests和limits的资源含义,以及Docker容器运行时的内存含义。我们在这里将介绍K8中的CPU的含义,以及CPU的requests和limits,并研究如何为Pod设置合理的cpu资源。那么,CPU在kubernetes... 查看详情

Prometheus 查询以获取 kubernetes pod 中的 CPU 和内存使用情况

...使用情况。有人可以帮忙吗?【问题讨论】:请提供更多关于您当前情况的信息。Promethe 查看详情

如何查看centos系统cpu/内存使用情况

...择按进程查看或者按用户查看,如想查看oracle用户的进程内存使用情况可以使用如下的命令:  $top-uoracle2.释义:PID:进程的ID  USER:进程所有者  PR:进程的优先级别,越小越优先被执行  NInice:值  VIRT:进程占用... 查看详情

linux查看cpu和内存使用情况

 在系统维护的过程中,随时可能有需要查看CPU使用率,并根据相应信息分析系统状况的需要。在CentOS中,可以通过top命令来查看CPU使用状况。运行top命令后,CPU使用状态会以全屏的方式显示,并且会处在对话的模式--用基于t... 查看详情