- notageek.it di Mirko Iodice - http://www.notageek.it -

Script WSH: limitare il consumo di CPU

Eseguendo via WSH pesanti interrogazioni su Database o File System ho notato che entrambi i motori (cscript/wscript) tendono a consumare moltissima CPU (fino al 100%!) rubando preziose risorse anche ad alcuni processi prioritari e causando quindi pesanti rallenamenti nell'esecuzione del sistema e dei servizi.
Per ovviare a questo problema in passato ho cercato di "rallentare" in maniera artificiale l'esecuzione degli script inserendo alcuni "sleep" all'interno del codice sorgente.
Se pur questa non fosse una soluzione molto elegante si è rivelata piuttosto efficace ed estremamente facile da implementare, l'unica pecca era rappresentata dal fatto di dover spesso accettare tempi di esecuzione "allungati" dalle pause forzate delle istruzioni "sleep".
Di recente, durante la realizzazione di un nuovo progetto, ho sentito il bisogno di trovare un metodo migliore del precedente per rendere gli script meno aggressivi sulle risorse del sistema, ecco come ho fatto:

Dim objWMI, objProc, ColProcs
If LCase(Right(WScript.FullName, 11)) = "cscript.exe" Then
	Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
	Set ColProcs = objWMI.ExecQuery("SELECT * FROM Win32_Process WHERE Name='cscript.exe'")
	For Each objProc in ColProcs
		If (InStr(LCase(objProc.CommandLine), LCase(WScript.ScriptName)) > 0) Then
			objProc.SetPriority 64
		End If
	Next
	Set objWMI = Nothing
Else
	Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
	Set ColProcs = objWMI.ExecQuery("SELECT * FROM Win32_Process WHERE Name='wscript.exe'")
	For Each objProc in ColProcs
		If (InStr(LCase(objProc.CommandLine), LCase(WScript.ScriptName)) > 0) Then
			objProc.SetPriority 64
		End If
	Next
	Set objWMI = Nothing
End If

Inserendo questo codice all'inizio di qualsiasi script si può fare in modo che il processo incaricato di eseguirlo abbia, nel sistema, la minor priorità possibile.

L'unica nota dolente di questo approccio basato su WMI è che non funziona su Windows 2000 poiché la proprietà "CommandLine" della classe "Win32_Process" è stata introdotta da Windows XP.

Per evitare il verificarsi di errori su Windows 2000 vi consiglio di arricchirlo con una funzione in grado di discriminare la versione del sistema operativo, ad esempio:

Dim objWMI, objProc, ColProcs
If Not IsWin2000 Then
	If LCase(Right(WScript.FullName, 11)) = "cscript.exe" Then
		Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
		Set ColProcs = objWMI.ExecQuery("SELECT * FROM Win32_Process WHERE Name='cscript.exe'")
		For Each objProc in ColProcs
			If (InStr(LCase(objProc.CommandLine), LCase(WScript.ScriptName)) > 0) Then
				objProc.SetPriority 64
			End If
		Next
		Set objWMI = Nothing
	Else
		Set objWMI = GetObject("winmgmts:\\.\root\cimv2")
		Set ColProcs = objWMI.ExecQuery("SELECT * FROM Win32_Process WHERE Name='wscript.exe'")
		For Each objProc in ColProcs
			If (InStr(LCase(objProc.CommandLine), LCase(WScript.ScriptName)) > 0) Then
				objProc.SetPriority 64
			End If
		Next
		Set objWMI = Nothing
	End If
End If

Function IsWin2000
	Dim TmpObjWMI, TmpObjOS, TmpColOSs
	IsWin2000 = False
	Set TmpObjWMI = GetObject("winmgmts:\\.\root\cimv2")
	Set TmpColOSs = TmpObjWMI.ExecQuery ("Select * from Win32_OperatingSystem")
	For Each TmpObjOS in TmpColOSs
		If (Instr(LCase(TmpObjOS.Caption), Lcase("2000")) > 0) Then
			IsWin2000 = True
		End If
	Next
	Set TmpObjWMI = Nothing
End Function

Autore

Mirko Iodice
mirko -at- notageek (.dot) it