2012-03-20 32 views
8

Una aplicación que estoy contribuyendo a disparar un componente escrito en C.¿Se puede limitar el uso de CPU en un objeto de proceso .NET?

El proceso C hace un crujido muy pesado y si no tiene cuidado realmente puede martillar su CPU.

¿Hay alguna manera de establecer un límite para los procesos externos generados por .NET?

He visto this artivcle al establecer un límite de memoria dura en el nivel del sistema operativo, ¿hay algo similar para la CPU?

+3

Puede cambiar la prioridad del proceso (creo que incluso puede ser una opción en 'ProcessStartInfo'). En realidad, no limita la cantidad de tiempo de procesador que obtendrá, pero le indicará al sistema operativo que permita que otros procesos tengan prioridad. –

Respuesta

9

No en Windows. Sin embargo, puede reducir la prioridad del proceso, lo que reducirá la probabilidad de que el proceso problemático se programe en la CPU e interfiera con otras aplicaciones (presumiblemente de mayor prioridad). Por ejemplo, desde http://dotnet-concepts-queries-interviews.blogspot.com/2007/05/how-to-set-process-priority-in-net.html:

Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.BelowNormal; 

Tenga en cuenta, si usted no tiene otra cosa que se ejecuta en la caja, es probable que desee este proceso de consumir toda la CPU disponible.

También puede configurar la afinidad de la CPU si está en una caja de multiprocesador, lo que limita el procesamiento a ciertos núcleos y deja otros libres para otras aplicaciones. En general, el sistema operativo hace un buen trabajo de programación de subprocesos de aplicación, por lo que establecer la prioridad del proceso es probable que tenga un mejor resultado general. Ver How Can I Set Processor Affinity in .NET?

+3

Vale la pena señalar ** esta respuesta es incorrecta ** dadas las versiones actuales de Windows; esto se puede hacer a través de las API de 'Job Object' en Win2012/Win8, en el momento en que se respondió esta pregunta, usted podría usar' NtSetInformationProcess' 'QUOTA_LIMITS_EX :: CPU_RATE_LIMIT' en Vista/Win7/Win2008. Por favor revise otras respuestas y material en línea antes de darse por vencido. Además, establecer la clase de prioridad también afecta las tasas de IO, no solo las tasas de CPU, que pueden tener efectos involuntarios si su objetivo NO fue degradar el rendimiento IO. –

+0

@ShaunWilson ¿Tiene una muestra de código de trabajo que muestre esto? Todavía no he logrado hacer que esto funcione. – i3arnon

7

Tuve el mismo problema. Lo resolví utilizando SetInformationJobObject Kernel32 Win Api y JOBOBJECT_CPU_RATE_CONTROL_INFORMATION struct.

Mi mayor problema fue representar esta estructura en C# (usa "unión"). Afortunadamente, encontré una descripción "mono" de esta estructura.

[StructLayout(LayoutKind.Explicit)] 
//[CLSCompliant(false)] 
struct JOBOBJECT_CPU_RATE_CONTROL_INFORMATION 
{ 
    [FieldOffset(0)] 
    public UInt32 ControlFlags; 
    [FieldOffset(4)] 
    public UInt32 CpuRate; 
    [FieldOffset(4)] 
    public UInt32 Weight; 
} 

Para activar la limitación Cpu:

ControlFlags = 0x00000001 | 0x00000004; 
CpuRate = percent of max usage * 100 (ex 50 * 100 for a 50% limit) 

El ejemplo siguiente es completamente funcional.

Espero que sea de ayuda.

Saludos cordiales

-Thierry-

[DllImport("kernel32.dll", EntryPoint = "CreateJobObjectW", CharSet = CharSet.Unicode)] 
public static extern IntPtr CreateJobObject(SecurityAttributes JobAttributes, string lpName); 

[DllImport("kernel32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool AssignProcessToJobObject(IntPtr hJob, IntPtr hProcess); 

[DllImport("kernel32.dll")] 
static extern bool SetInformationJobObject(IntPtr hJob, JOBOBJECTINFOCLASS JobObjectInfoClass, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength); 

public class SecurityAttributes 
{ 

    public int nLength; 
    public IntPtr pSecurityDescriptor; 
    public bool bInheritHandle; 

    public SecurityAttributes() 
    { 
     this.bInheritHandle = true; 
     this.nLength = 0; 
     this.pSecurityDescriptor = IntPtr.Zero; 
    } 
} 

public enum JOBOBJECTINFOCLASS 
{ 
    JobObjectAssociateCompletionPortInformation = 7, 
    JobObjectBasicLimitInformation = 2, 
    JobObjectBasicUIRestrictions = 4, 
    JobObjectEndOfJobTimeInformation = 6, 
    JobObjectExtendedLimitInformation = 9, 
    JobObjectSecurityLimitInformation = 5, 
    JobObjectCpuRateControlInformation = 15 
} 

[StructLayout(LayoutKind.Explicit)] 
//[CLSCompliant(false)] 
struct JOBOBJECT_CPU_RATE_CONTROL_INFORMATION 
{ 
    [FieldOffset(0)] 
    public UInt32 ControlFlags; 
    [FieldOffset(4)] 
    public UInt32 CpuRate; 
    [FieldOffset(4)] 
    public UInt32 Weight; 
} 

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

/// <summary> 
/// Launch the legacy application with some options set. 
/// </summary> 
static void DoExecuteProgramm() 
{ 
    // prepare the process to execute 
    var startInfo = new ProcessStartInfo(); 
    . . . . . 
    // Start the process 
    var process = Process.Start(startInfo); 

    //Limit the CPU usage to 45% 
    var jobHandle = CreateJobObject(null, null); 
    AssignProcessToJobObject(jobHandle, process.Handle); 
    var cpuLimits = new JOBOBJECT_CPU_RATE_CONTROL_INFORMATION(); 
    cpuLimits.ControlFlags = (UInt32)(CpuFlags.JOB_OBJECT_CPU_RATE_CONTROL_ENABLE | CpuFlags.JOB_OBJECT_CPU_RATE_CONTROL_HARD_CAP); 
    cpuLimits.CpuRate = 45 * 100; // Limit CPu usage to 45% 
    var pointerToJobCpuLimits = Marshal.AllocHGlobal(Marshal.SizeOf(cpuLimits)); 
    Marshal.StructureToPtr(cpuLimits, pointerToJobCpuLimits, false); 
    if (!SetInformationJobObject(jobHandle, JOBOBJECTINFOCLASS.JobObjectCpuRateControlInformation, pointerToJobCpuLimits, (uint)Marshal.SizeOf(cpuLimits))) 
    { 
     Console.WriteLine("Error !"); 
    } 
} 
+0

Fascinante, siempre me olvido de los objetos de trabajo de Windows, podría ser bastante útil. Desafortunadamente, el indicador 'JobObjectCpuRateControlInformation' solo es compatible con Win8 y versiones posteriores. –

+0

Desafortunadamente, sí ... Lo usé para la gestión de procesos en un servidor de Windows 2012 (requisito de seguridad). –

+0

Gracias por su código. Este código funciona para mí, pero me pregunto si configuré el uso del límite de CPU en un 45%, pero usa un 54-50% ... ¿sabes por qué? –

Cuestiones relacionadas