开发者

How to Limit CPU Usage in C#

开发者 https://www.devze.com 2022-12-13 13:05 出处:网络
I\'m making a C# program. My program is calling another program. The problem is the program that I am calling is consuming 100% of the CPU. So I want 开发者_如何学JAVAto limit it to a constant percent

I'm making a C# program. My program is calling another program. The problem is the program that I am calling is consuming 100% of the CPU. So I want 开发者_如何学JAVAto limit it to a constant percentage of CPU usage. Is it possible? How?


Is there any reason why you want to limit it to a specific percent of CPU usage? What about running it in lower priority, so that it still uses 100% of the CPU when nothing else requires it but gets put in the background when there are more important processes running?


This is still a relatively high result in search engines, so I'll add an answer to this old question:

YES!

With Windows 8+, you can limit a processes CPU consumption with Jobs:

Call SetInformationJobObject with JobObjectCpuRateControlInformation and set JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP.

The Job API is native so you'll have to p/invoke to it:

    public static class Win32
    {
        public enum JobObjectInfoType
        {
            AssociateCompletionPortInformation = 7,
            BasicLimitInformation = 2,
            BasicUIRestrictions = 4,
            EndOfJobTimeInformation = 6,
            ExtendedLimitInformation = 9,
            SecurityLimitInformation = 5,
            GroupInformation = 11,
            JobObjectCpuRateControlInformation = 15
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct JOBOBJECT_BASIC_LIMIT_INFORMATION
        {
            public Int64 PerProcessUserTimeLimit;
            public Int64 PerJobUserTimeLimit;
            public JOBOBJECTLIMIT LimitFlags;
            public UIntPtr MinimumWorkingSetSize;
            public UIntPtr MaximumWorkingSetSize;
            public UInt32 ActiveProcessLimit;
            public Int64 Affinity;
            public UInt32 PriorityClass;
            public UInt32 SchedulingClass;
        }

        [Flags]
        public enum JOBOBJECTLIMIT : uint
        {
            JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x2000,
            JOB_OBJECT_LIMIT_JOB_MEMORY = 0x00000200,
            JOB_OBJECT_LIMIT_PROCESS_MEMORY = 0x00000100,
            JOB_OBJECT_LIMIT_WORKINGSET = 0x00000001
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct IO_COUNTERS
        {
            public UInt64 ReadOperationCount;
            public UInt64 WriteOperationCount;
            public UInt64 OtherOperationCount;
            public UInt64 ReadTransferCount;
            public UInt64 WriteTransferCount;
            public UInt64 OtherTransferCount;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION
        {
            public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
            public IO_COUNTERS IoInfo;
            public UIntPtr ProcessMemoryLimit;
            public UIntPtr JobMemoryLimit;
            public UIntPtr PeakProcessMemoryUsed;
            public UIntPtr PeakJobMemoryUsed;
        }

        public enum CpuFlags : UInt32
        {
            JOB_OBJECT_CPU_RATE_CONTROL_ENABLE = 0x00000001,
            JOB_OBJECT_CPU_RATE_CONTROL_WEIGHT_BASED = 0x00000002,
            JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP = 0x00000004
        }

        // https://stackoverflow.com/a/31361144
        [StructLayout(LayoutKind.Explicit)]
        //[CLSCompliant(false)]
        public struct JOBOBJECT_CPU_RATE_CONTROL_INFORMATION
        {
            [FieldOffset(0)]
            public CpuFlags ControlFlags;
            [FieldOffset(4)]
            public UInt32 CpuRate;
            [FieldOffset(4)]
            public UInt32 Weight;
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string name);

        [DllImport("kernel32.dll")]
        internal static extern bool SetInformationJobObject(IntPtr job, JobObjectInfoType infoType,
            ref JOBOBJECT_EXTENDED_LIMIT_INFORMATION lpJobObjectInfo, uint cbJobObjectInfoLength);

        [DllImport("kernel32.dll")]
        internal static extern bool SetInformationJobObject(IntPtr job, JobObjectInfoType infoType,
            ref JOBOBJECT_CPU_RATE_CONTROL_INFORMATION lpJobObjectInfo, uint cbJobObjectInfoLength);

        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
    }

    public class JobUtils
    {
        ///
        public static void SetExtendedLimitInformationJobObject(IntPtr jobHandle, JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo)
        {
            int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));

            if (!Win32.SetInformationJobObject(jobHandle, JobObjectInfoType.ExtendedLimitInformation,
                ref extendedInfo, (uint)length))
            {
                throw new Win32Exception();
            }
        }


        ///
        public static void SetCpuRateControlInformationJobObject(IntPtr jobHandle, JOBOBJECT_CPU_RATE_CONTROL_INFORMATION cpuRateControlInformation)
        {
            int length = Marshal.SizeOf(typeof(JOBOBJECT_CPU_RATE_CONTROL_INFORMATION));

            if (!Win32.SetInformationJobObject(jobHandle, JobObjectInfoType.JobObjectCpuRateControlInformation,
                ref cpuRateControlInformation, (uint)length))
            {
                throw new Win32Exception();
            }
        }

        ///
        public static void AssignProcessToJobObject(IntPtr job, Process process)
        {
            bool success = Win32.AssignProcessToJobObject(job, process.Handle);

            if (!success && !process.HasExited)
                throw new Win32Exception();
        }
    }


                // test code
                var cpuLimit = 20; // 20%
                var job = Win32.CreateJobObject(IntPtr.Zero, null);
                JobUtils.SetCpuRateControlInformationJobObject(job, new Win32.JOBOBJECT_CPU_RATE_CONTROL_INFORMATION
                {
                    ControlFlags = Win32.CpuFlags.JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | Win32.CpuFlags.JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP,
                    CpuRate = (uint)cpuLimit * 100
                });
                JobUtils.AssignProcessToJobObject(job, Process.GetCurrentProcess());


The operating system should handle the time sharing between your two applications. There is probably a good reason your application is using 100% of the CPU, it is calculating something. If you need to wait for the completion of another process then you can use Process.WaitForExit to halt the execution of the calling thread while the other process completes.

0

精彩评论

暂无评论...
验证码 换一张
取 消