问题
Of late, I\'m becoming more health oriented when constructing my program, I have observed that most of programs take 2 or 3 minutes to execute and when I check on the task scheduler, I see that they consume 100% of CPU usage, can I limit this usage programatically in code? This will certainly enable me to run multiple programs at a given time.
Thanks, Nidhi
回答1:
That's not your concern... It's the job of the operating system to distribute processor time between running processes. If you'd like to give other processes first crack at getting their stuff done, then simply reduce the priority of your own process by modifying the Process.PriorityClass value for it.
See also: Windows Equivalent of ‘nice’
回答2:
This thread is over four years old, and it still annoys me that the accepted answer criticizes the question rather than answering it. There are many valid reasons you would want to limit the CPU time taken by your program, I can list a few off the top of my head.
It might seem like a waste not to use all free CPU cycles available, but this mentality is flawed. Unlike older CPUs, most modern CPUs do not run at a fixed clock speed - many have power saving modes where they drop the clock speed and cpu voltage when load is low. CPUs also consume more power when performing calculations than they do running NOOPs. This is especially relevant to laptops that require fans to cool the CPU when it is under high load. Running a task at 100% for a short time can use far more energy than running a task at 25% for four times as long.
Imagine you are writing a background task that is designed to index files periodically in the background. Should the indexing task use as much of the CPU as it can at a lower priority, or throttle itself to 25% and take as long as it needs? Well, if it were to consume 100% of the CPU on a laptop, the CPU would heat up, the fans would kick in, and the battery would drain fairly quickly, and the user would get annoyed. If the indexing service throttled itself, the laptop may be able to run with completely passive cooling at a very low cpu clock speed and voltage.
Incidentally, the Windows Indexing Service now throttles itself in newer versions of Windows, which it never did in older versions. For an example of a service that still doesn't throttle itself and frequently annoys people, see Windows Installer Module.
An example of how to throttle part of your application internally in C#:
public void ThrottledLoop(Action action, int cpuPercentageLimit) {
Stopwatch stopwatch = new Stopwatch();
while(true) {
stopwatch.Reset();
stopwatch.Start();
long actionStart = stopwatch.ElapsedTicks;
action.Invoke();
long actionEnd = stopwatch.ElapsedTicks;
long actionDuration = actionEnd - actionStart;
long relativeWaitTime = (int)(
(1/(double)cpuPercentageLimit) * actionDuration);
Thread.Sleep((int)((relativeWaitTime / (double)Stopwatch.Frequency) * 1000));
}
}
回答3:
First of all, I agree with Ryan that the question is perfectly valid and there are cases where thread priorities are not at all sufficient. The other answers appear highly theoretical and of no practical use in situations where the application is properly designed but still needs to be throttled. Ryan offers a simple solution for cases in which a relatively short task is performed in high frequency. There are cases, however, when the task takes a very long time (say a minute or so) and you cannot or don't want to break it into smaller chunks between which you can do the throttling. For these cases the following solution might be helpful:
Rather that implementing throttling into the business code, you can design the algorithm itself to work at full steam and simply throttle the thread which runs the operation "from the outside". The general approach is the same as in Ryan's answer: Calculate a suspension time based on the current usage and suspend the thread for this timespan before resuming it again. Given a process which you want to throttle, this is the logic:
public static class ProcessManager
{
[Flags]
public enum ThreadAccess : int
{
TERMINATE = (0x0001),
SUSPEND_RESUME = (0x0002),
GET_CONTEXT = (0x0008),
SET_CONTEXT = (0x0010),
SET_INFORMATION = (0x0020),
QUERY_INFORMATION = (0x0040),
SET_THREAD_TOKEN = (0x0080),
IMPERSONATE = (0x0100),
DIRECT_IMPERSONATION = (0x0200)
}
[DllImport("kernel32.dll")]
static extern IntPtr OpenThread(ThreadAccess dwDesiredAccess, bool bInheritHandle, uint dwThreadId);
[DllImport("kernel32.dll")]
static extern uint SuspendThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int ResumeThread(IntPtr hThread);
[DllImport("kernel32.dll")]
static extern int CloseHandle(IntPtr hThread);
public static void ThrottleProcess(int processId, double limit)
{
var process = Process.GetProcessById(processId);
var processName = process.ProcessName;
var p = new PerformanceCounter("Process", "% Processor Time", processName);
while (true)
{
var interval = 100;
Thread.Sleep(interval);
var currentUsage = p.NextValue() / Environment.ProcessorCount;
if (currentUsage < limit) continue;
var suspensionTime = (currentUsage-limit) / currentUsage * interval;
SuspendProcess(processId);
Thread.Sleep((int)suspensionTime);
ResumeProcess(processId);
}
}
private static void SuspendProcess(int pid)
{
var process = Process.GetProcessById(pid);
if (process.ProcessName == string.Empty)
return;
foreach (ProcessThread pT in process.Threads)
{
IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
{
continue;
}
SuspendThread(pOpenThread);
CloseHandle(pOpenThread);
}
}
private static void ResumeProcess(int pid)
{
var process = Process.GetProcessById(pid);
if (process.ProcessName == string.Empty)
return;
foreach (ProcessThread pT in process.Threads)
{
IntPtr pOpenThread = OpenThread(ThreadAccess.SUSPEND_RESUME, false, (uint)pT.Id);
if (pOpenThread == IntPtr.Zero)
{
continue;
}
var suspendCount = 0;
do
{
suspendCount = ResumeThread(pOpenThread);
} while (suspendCount > 0);
CloseHandle(pOpenThread);
}
}
}
The benefit of this solution is that the checking interval becomes independent of the duration of your "long running task". Furthermore, business logic and throttling logic are separated. The suspense/resume code is inspired by this thread. Please note that disposal and ending the throttling needs to be implemented in the solution above, it is not production code.
回答4:
You could write a Governor
class that throttles the CPU usage. This class would contain a utility method that should be called on a regular basis (e.g. calling this utility function within a while loop of your function) by your CPU bound function. The governor would check if the amount of time elapsed exceeded a particular threshold, and then sleep for a period of time so as to not consume all the CPU.
Here's a simple Java implementation off the top of my head (just so you get the idea) that will throttle the CPU usage to 50% if you have a single threaded CPU bound function.
public class Governor
{
long start_time;
public Governor()
{
this.start_time = System.currentTimeMillis();
}
public void throttle()
{
long time_elapsed = System.currentTimeMillis() - this.start_time;
if (time_elapsed > 100) //throttle whenever at least a 100 millis of work has been done
{
try { Thread.sleep(time_elapsed); } catch (InterruptedExceptione ie) {} //sleep the same amount of time
this.start_time = System.currentTimeMillis(); //reset after sleeping.
}
}
}
Your CPU bound function would instantiate a Governor
, and then just call throttle
on a regular basis within the function.
回答5:
Thank all of you for answering. I've been working on this and the exe it runs for a few hours and want to share to help others. I wrote a class I'm going to set and forget in a WPF app that'll encrypt and push data to the cloud, but I couldn't ever have it ever interfere with the timing of the WPF app and what the WPF app needs in the way of resources, which I am also going to add a flag to disable when the WPF app is in it's highest resource consumption state. I've already highly threaded this WPF with the TPL. This solution has both the priority set of the process
myProcess.PriorityClass = ProcessPriorityClass.Idle;
and the CPU percentage limited.
then in my mainDisplay.xaml.cs I'll use
ProcessManagement.StartProcess(5);
in MainWindow()
And there is no window popping up when that exe is run
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
in the object initalizer
internal class ProcessManagement
{
private static int CpuPercentageLimit { get; set; }
public static void StartProcess(int cpuPercent)
{
CpuPercentageLimit = cpuPercent;
var stopwatch = new Stopwatch();
while (true)
{
stopwatch.Reset();
stopwatch.Start();
var actionStart = stopwatch.ElapsedTicks;
try
{
var myProcess = new Process
{
StartInfo =
{
FileName = @"D:\\Source\\ExeProgram\\ExeProgram\\bin\\Debug\\ExeProgram.exe",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
myProcess.Start();
myProcess.PriorityClass = ProcessPriorityClass.Idle;
myProcess.Refresh();
myProcess.WaitForExit();
var actionEnd = stopwatch.ElapsedTicks;
var actionDuration = actionEnd - actionStart;
long relativeWaitTime = (int)((1 / (double)CpuPercentageLimit) * actionDuration);
var sleepTime = (int)((relativeWaitTime / (double)Stopwatch.Frequency) * 1000);
Thread.Sleep(sleepTime);
myProcess.Close();
}
catch (Exception e)
{
// ignored
}
}
}
}
In my application, there is ample time, like 24/7/365, to upload lots of data, including thousands of images, but the UI also needs to stay active when used and when the system runs, nothing else can be running.
回答6:
If you have a multi core processor, you can set the Affinity on each process to only use which cores you want it to use. This is the closest method I know of. But it will only allow you to assign percentages that are a factor of 50% on a dual core, and 25% on a quad core.
回答7:
You can run your program in a thread with a lower threadpriority, the rest is up to your operating system. Having a process eat up 100% of your CPU is not bad. My SETI is usually taking up all my remaining CPU time without bothering my other programs. It only gets a problem when your thread gets priority over more important programs.
回答8:
If you code is running at all, it is at 100%
I suppose slipping in some sleeps might have an effect.
I have to wonder about that 2-3 minute figure. I've seen it too, and I suppose it's loading and initializing lots of stuff I probably don't really need.
回答9:
According to MSDN, you can only set a thread priority, i.e.
var t1 = new Thread(() => doSomething());
t1.Priority = ThreadPriority.BelowNormal;
t1.Start();
where doSomething is the function you want to create a thead for. The priority can be one of the ThreadPriority enumeration members Lowest, BelowNormal, Normal, AboveNormal, Highest
- for a description see the MSDN link above. Priority Normal
is the default.
Note that CPU usage also depends on how many cores and logical processors your physical CPU has *) - and how the threads and processes are assigned to those cores (the assignment to a dedicated processor is called "processor affinity" - if you want to know more about that, see this StackOverflow question).
*) To find that out, open the task manager (via Ctrl+Alt+Delete - select "task manager"), go to Performance and select CPU there: Below the utilization graph you can see "Cores" and "Logical processors".
A core is a physical unit built into the CPU, while a logical processor is just an abstraction, which means the more cores your CPU consists of, the faster it can process parallel tasks.
回答10:
I honestly think rather than worry about trying to limit CPU utilization by your app, you should focus more of your energies on profiling the application to uncover and correct bottlenecks and inefficiencies that may exist.
回答11:
If there is no other task running, is it wrong for your app to use all the cpu capacity that is available? It is available, as in it's there and it is free to use. So use it!
If you somehow limit the cpu usage of your task, it will take longer to complete. But it will still take the same number of cpu cycles, so you gain nothing. You just slow down your application.
Don't do it. Don't even try it. There's no reason why you should.
回答12:
I think what you need to do is to understand the performance problem in your application instead of trying to put a cap on the CPU usage. You Can use Visual Studio Profiler to see why you application is taking 100% CPU for 2-3 minutes in the first place. This should reveal the hot spot in your app, and then you can be able to address this issue.
If you are asking in general regarding how to do resource throttling in windows, then you can look at the "Task" objects, Job objects allows you to set limits such as Working set, process priority...etc.
You can check out the Job objects documentation here http://msdn.microsoft.com/en-ca/library/ms684161(VS.85).aspx Hope this helps. Thanks
来源:https://stackoverflow.com/questions/989281/how-can-i-programmatically-limit-my-programs-cpu-usage-to-below-70