c# - ¿Cómo puedo limitar programáticamente el uso de la CPU de mi programa a menos del 70%?
performance cpu-usage (12)
Creo que lo que debes hacer es comprender el problema de rendimiento en tu aplicación en lugar de intentar limitar el uso de la CPU. Puede usar Visual Studio Profiler para ver por qué su aplicación está tomando 100% de CPU por 2-3 minutos en primer lugar. Esto debería revelar el punto caliente en su aplicación, y luego puede ser capaz de abordar este problema.
Si está preguntando en general sobre cómo hacer estrangulamiento de recursos en Windows, entonces puede mirar los objetos de "Tarea", Objetos de trabajo le permite establecer límites como Conjunto de trabajo, Prioridad de proceso ... etc.
Puede consultar la documentación de objetos de trabajo aquí http://msdn.microsoft.com/en-ca/library/ms684161(VS.85).aspx Espero que esto ayude. Gracias
Últimamente, me estoy volviendo más orientado a la salud al construir mi programa, he observado que la mayoría de los programas tardan 2 o 3 minutos en ejecutarse y cuando reviso el programador de tareas, veo que consumen el 100% del uso de la CPU, ¿Limito este uso programáticamente en el código? Esto ciertamente me permitirá ejecutar múltiples programas en un momento dado.
Gracias, Nidhi
En primer lugar, estoy de acuerdo con Ryan en que la pregunta es perfectamente válida y hay casos en los que las prioridades de los hilos no son suficientes en absoluto. Las otras respuestas parecen altamente teóricas y de ningún uso práctico en situaciones donde la aplicación está diseñada correctamente, pero aún necesita ser acelerada. Ryan ofrece una solución simple para casos en los que se realiza una tarea relativamente corta en alta frecuencia. Sin embargo, hay casos en que la tarea lleva mucho tiempo (digamos un minuto más o menos) y no puede o no quiere dividirla en trozos más pequeños entre los cuales puede hacer la aceleración. Para estos casos, la siguiente solución podría ser útil:
En lugar de implementar la aceleración en el código comercial, puede diseñar el algoritmo para que funcione a pleno rendimiento y simplemente estrangular el hilo que ejecuta la operación "desde afuera". El enfoque general es el mismo que en la respuesta de Ryan: calcule un tiempo de suspensión basado en el uso actual y suspenda el hilo para este período de tiempo antes de reanudarlo. Dado un proceso que desea acelerar, esta es la lógica:
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);
}
}
}
El beneficio de esta solución es que el intervalo de verificación se vuelve independiente de la duración de su "tarea de larga ejecución". Además, la lógica de negocios y la lógica de estrangulamiento están separadas. El código de suspenso / reanudación está inspirado en este hilo . Tenga en cuenta que la eliminación y el final de la aceleración deben implementarse en la solución anterior, no es un código de producción.
Este hilo tiene más de cuatro años, y todavía me molesta que la respuesta aceptada critique la pregunta en lugar de responderla. Hay muchas razones válidas por las que desearía limitar el tiempo de CPU que toma su programa, puedo enumerar algunas de ellas en la parte superior de mi cabeza.
Puede parecer un desperdicio no utilizar todos los ciclos de CPU libres disponibles, pero esta mentalidad es defectuosa. A diferencia de las CPUs más antiguas, la mayoría de las CPU modernas no funcionan a una velocidad de reloj fija; muchas tienen modos de ahorro de energía en las que reducen la velocidad del reloj y el voltaje de la CPU cuando la carga es baja . Las CPU también consumen más energía cuando realizan cálculos que lo hacen ejecutando NOOP. Esto es especialmente relevante para las computadoras portátiles que requieren ventiladores para enfriar la CPU cuando está bajo carga alta. Ejecutar una tarea al 100% durante un tiempo corto puede usar mucha más energía que ejecutar una tarea al 25% durante cuatro veces más.
Imagine que está escribiendo una tarea en segundo plano que está diseñada para indexar archivos periódicamente en segundo plano. ¿Debería la tarea de indexación usar la mayor cantidad de CPU posible con una prioridad más baja, o acelerarse hasta el 25% y tomar el tiempo que necesite? Bueno, si consumiera el 100% de la CPU en una computadora portátil, la CPU se calentaría, los ventiladores entrarían en funcionamiento y la batería se agotaría bastante rápido, y el usuario se enojaría. Si el servicio de indexación se acelera, la computadora portátil puede funcionar con refrigeración completamente pasiva a una velocidad y voltaje de reloj de la CPU muy bajos.
Dicho sea de paso, Windows Indexing Service ahora se acelera en las versiones más nuevas de Windows, lo que nunca sucedió en las versiones anteriores. Para obtener un ejemplo de un servicio que aún no se regula y con frecuencia molesta a las personas, consulte el Módulo de instalación de Windows.
Un ejemplo de cómo estrangular internamente parte de su aplicación en 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));
}
}
Gracias a todos por responder. He estado trabajando en esto y el exe se ejecuta durante unas horas y quiero compartir para ayudar a otros. Escribí una clase que voy a configurar y olvidar en una aplicación WPF que encriptará y enviará datos a la nube, pero nunca podría haber interferido con el tiempo de la aplicación WPF y con lo que necesita la aplicación WPF. en el camino de los recursos, que también voy a agregar un indicador para deshabilitar cuando la aplicación WPF se encuentre en su estado de mayor consumo de recursos. Ya he enhebrado este WPF con el TPL. Esta solución tiene el conjunto de prioridades del proceso
myProcess.PriorityClass = ProcessPriorityClass.Idle;
y el porcentaje de CPU limitado.
entonces en mi mainDisplay.xaml.cs lo usaré
ProcessManagement.StartProcess(5);
en MainWindow ()
Y no aparece una ventana cuando se ejecuta ese exe
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
en el iniciador de objetos
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//RemMon//RemMon//bin//Debug//RemMon.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
}
}
}
}
En mi aplicación, hay suficiente tiempo, como 24/7/365, para cargar muchos datos, incluidos miles de imágenes, pero la IU también necesita mantenerse activa cuando se usa y cuando el sistema se ejecuta, no se puede ejecutar nada más.
Honestamente creo que en lugar de preocuparse por tratar de limitar la utilización de la CPU por su aplicación, debe concentrar más energías en perfilar la aplicación para descubrir y corregir los cuellos de botella e ineficiencias que puedan existir.
Podría escribir una clase de Governor
que acelere el uso de la CPU. Esta clase contendría un método de utilidad que debería invocarse regularmente (por ejemplo, llamar a esta función de utilidad dentro de un ciclo while de su función) mediante su función de límite de CPU. El gobernador verificará si la cantidad de tiempo transcurrido excedió un umbral particular, y luego dormirá por un período de tiempo para no consumir toda la CPU.
Aquí hay una simple implementación de Java (para que entiendas la idea) que acelerará el uso de CPU al 50% si tienes una función de límite de CPU con un solo subproceso.
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.
}
}
}
La función de límite de CPU creará una instancia de un Governor
, y luego solo llama al throttle
regularmente dentro de la función.
Puede ejecutar su programa en un subproceso con una threadpriority subproceso menor, el resto depende de su sistema operativo. Tener un proceso que consuma el 100% de tu CPU no es malo. Mi SETI generalmente ocupa todo el tiempo restante de la CPU sin molestar a mis otros programas. Solo se plantea un problema cuando el hilo tiene prioridad sobre los programas más importantes.
Según MSDN , solo puede establecer una prioridad de subproceso, es decir,
var t1 = new Thread(() => doSomething());
t1.Priority = ThreadPriority.BelowNormal;
t1.Start();
donde doSomething es la función para la que desea crear un thead. La prioridad puede ser uno de los miembros de la enumeración ThreadPriority. Lowest, BelowNormal, Normal, AboveNormal, Highest
: para obtener una descripción, consulte el enlace de MSDN anterior. Prioridad Normal
es el valor predeterminado.
Si el código se está ejecutando, está al 100%
Supongo que deslizarse en algunos sueños podría tener un efecto.
Tengo que preguntarme acerca de esa cifra de 2-3 minutos. Lo he visto también, y supongo que está cargando e inicializando muchas cosas que probablemente no necesito.
Si no hay otra tarea ejecutándose, ¿está mal que su aplicación use toda la capacidad de la CPU que está disponible? Está disponible , ya que está allí y es de uso gratuito . ¡Entonces úsalo!
Si de alguna manera limita el uso de la CPU de su tarea, llevará más tiempo completarla. Pero aún tomará la misma cantidad de ciclos de CPU, por lo que no obtendrá nada. Simplemente ralentiza su aplicación.
No lo hagas Ni siquiera lo intentes. No hay razón por la que deberías.
Si tiene un procesador multinúcleo, puede configurar Affinity en cada proceso para que solo use los núcleos que desea que use. Este es el método más cercano que conozco. Pero solo le permitirá asignar porcentajes que son un factor del 50% en un núcleo doble y del 25% en un núcleo cuádruple.
Esa no es su preocupación ... El trabajo del sistema operativo consiste en distribuir el tiempo del procesador entre los procesos en ejecución. Si desea dar prioridad a otros procesos para completar sus tareas, simplemente reduzca la prioridad de su propio proceso modificando el valor Process.PriorityClass
para ello.