퍼포먼스 카운터 알 아픈 디자인.

5044 단어 performance
에 있습니다.NET에서 프로세스의 성능 계수는 PerformanceCounter를 사용하여 프로세스의 CPU, 메모리 등 정보를 통계할 수 있습니다.정상적으로 사용하기에는 이 대상이 편리하지만, 같은 이름의 여러 프로세스에 대해 성능 계수를 하는 것은 정말 고통스럽다.PerformanceCounter가 여러 개의 같은 이름의 프로세스 계수에 직면한 문제를 상세하게 설명하십시오.

응용 상황


PerformanceCounter는 프로세스 실례 이름을 통해 계수를 감시하지만, 이 실례 이름은 운영체제에서 실시간으로 동적으로 분배되며, 같은 이름의 프로세스가 하나만 있다면 처리하기 쉽다.같은 이름의 프로세스가 여러 개 있으면 비극적인 일이 일어난다. 같은 이름의 프로세스가 생성되고 닫히면 다른 같은 이름의 프로세스의 실례명에 영향을 줄 수 있다.따라서 해당 PerformanceCounter와 프로세스의 대응 관계가 완전히 혼란스러워집니다.(정말 이해가 안 돼. NET가 이걸 이루는데 왜 PID를 안 쓰는지)
현재 ams-p.exe 프로그램이 세 번씩 열려 있다고 가정하면 대응하는 프로세스의 실례명은 다음과 같다.
1)ams-p.exe [pid:7012]
2)ams-p.exe#1 [pid:7013]
3)ams-p.exe#2 [pid:7014]
실례명 윈도우즈 시스템이 실시간으로 분배하기 때문에 같은 이름의 프로세스 수량이 변화하는 것을 발견하면 대응하는 프로세스의 실례명도 변합니다.상기 상황에 따라 2가 닫힌 후에 그 실례에 대응하는 관계는 다음과 같다.
1)ams-p.exe [pid:7012]
3)ams-p.exe#1 [pid:7014]
이렇게 하면 3에 대응하는 실례명이 존재하지 않고 Performance Counter의 통계 오류를 초래할 수 있다. 같은 이름에 대응하는 프로세스의 수가 더 많고 중간에 프로세스가 닫히면 대량의 Performance Counter 통계와 프로세스의 대응 관계에 오류가 발생할 수 있다.

해결책


해결 방법이 있지만 방법은 모두 매우 고통스럽다. Process의 Exite 사건을 감시하고 퇴출 상황에 따라 실례명과 PID의 대응 관계를 조정한다. 그러나 이런 방식은 문제가 존재한다. 만약에 다른 응용 프로그램도 이 프로세스명이고 다른 채널을 통해 당신이 귀속된 Exite 사건을 제때 잡지 못하면 계수 오류가 발생하는 비극적인 사건이 발생할 수 있다.또 다른 해결 방법은 전면적인 것이다. 모든 Performance Counter를 실행하기 전에 현재 시스템의 이 이름의 프로세스 정보를 가져와 업로드하고 실시간 실례명과 PID 대응 관계를 구축한 다음Performance Counter를 실행한 후에 실례명에 대응하는 PID 계수를 기록한다.구체적인 코드는 다음과 같습니다.
    class CPUCounter:IDisposable
    {
        public CPUCounter(string processName)
        {
            mProcessName = processName;
            mTimer = new System.Threading.Timer(GetUsage, null, 1000, 1000);
        }

        private System.Threading.Timer mTimer;

        private string mProcessName;

        private Dictionary<int, float> mProcessCpuUsage = new Dictionary<int, float>();

        private List<CounterItem> mCounters = new List<CounterItem>();

        private Dictionary<string, int> mProcessIDs = new Dictionary<string, int>();

        public float ProcessUsage(int pid)
        {
            float result = 0;
            mProcessCpuUsage.TryGetValue(pid, out result);
            return result;
        }

        private void OnCreateCounter(string processname)
        {
            CounterItem item = mCounters.Find(e => e.ProcessName == processname);
            if (item == null)
            {
                item = new CounterItem();
                item.Counter = new PerformanceCounter();
                item.Counter.CategoryName = "Processor";
                item.Counter.CounterName = "% Processor Time";
                item.Counter.InstanceName = processname;
            }
            item.Enabled = true;
        }

        private void GetUsage(object state)
        {
            mProcessIDs.Clear();
            Process[] ps = Process.GetProcessesByName(mProcessName);
            List<CounterItem> disposeditems = new List<CounterItem>();
            if (ps.Length == 1)
            {
                mProcessIDs.Add(mProcessName, ps[0].Id);
                OnCreateCounter(mProcessName);
            }
            else
            {
                for (int i = 1; i < ps.Length; i++)
                {
                    mProcessIDs.Add(mProcessName + "#" + i, ps[i].Id);
                    OnCreateCounter(mProcessName + "#" + i);
                }
            }
            foreach (CounterItem item in mCounters)
            {
                if (item.Enabled)
                {
                    mProcessCpuUsage[mProcessIDs[item.ProcessName]] = item.Counter.NextValue();
                    item.Enabled = false;
                }
                else
                {
                    disposeditems.Add(item);
                }
            }
            if(disposeditems.Count>0)
                foreach (CounterItem item in disposeditems)
                {
                    mCounters.Remove(item);
                }
        }

        class CounterItem
        {
            public string ProcessName { get; set; }

            public System.Diagnostics.PerformanceCounter Counter
            {
                get;
                set;
            }
           
            public bool Enabled
            {
                get;
                set;
            }
        }

        public void Dispose()
        {
            if (mTimer != null)
                mTimer.Dispose();
        }
    }

만약 더 좋은 방법이 있는 학우가 방심하지 않고 공유한다면

좋은 웹페이지 즐겨찾기