我有这项服务,当收到请求时,运行powershell命令并返回结果。这是调用者类代码:
public class PowerShellScript {
public PowerShellScript() {
}
public Object[] Invoke( String strScriptName, NameValueCollection nvcParams ) {
Boolean bResult = true;
int n = 0;
Object[] objResult = null;
PowerShell ps = PowerShell.Create();
String strScript = strScriptName;
for (n = 0; n < nvcParams.Count; n++) {
strScript += String.Format( " -{0} {1}", nvcParams.GetKey( n ), nvcParams[n] );
}
//ps.AddScript( @"E:\snapins\Init-profile.ps1" );
ps.AddScript( strScript );
Collection<PSObject> colpsOutput = ps.Invoke();
if (colpsOutput.Count > 0)
objResult = new Object[colpsOutput.Count];
n = 0;
foreach (PSObject psOutput in colpsOutput) {
if (psOutput != null) {
try {
objResult[n] = psOutput.BaseObject;
}
catch (Exception ex) {
//exception should be handeled properly in powershell script
}
}
n++;
}
colpsOutput.Clear();
ps.Dispose();
return objResult;
}
}
Method Invoke返回powershell脚本返回的所有结果。
一切都很好。只要它在单个线程中运行。由于我们调用的一些powershell脚本可能需要一个小时才能完成,我们不希望服务在那段时间内什么都不做,我们决定采用多线程。 不幸的是,Powershell类不是线程安全的,导致严重的内存泄漏和CPU烧毁率。但是,如果我在Invoke方法上使用锁定,这将意味着我们为什么进入多线程的整个想法将会消失。
任何想法如何解决这个问题?
答案 0 :(得分:1)
您可以使用BeginInvoke()
类的PowerShell
方法代替您使用的Invoke()
类。在这种情况下,您异步执行脚本,不要阻止调用线程。但是你也必须检查你的整个场景。您的旧同步方法会返回在调用后可以轻松使用的结果。在新的异步方法中,这是不可能的。
见 http://msdn.microsoft.com/en-us/library/system.management.automation.powershell.begininvoke
答案 1 :(得分:1)
无论如何......在执行powershell命令时,我放弃了多线程。我创建了一个能够执行powershell脚本的小程序。然后,每个线程为该程序创建新进程。我知道这有点开销,但它确实有用。
基本上,Powershell类不是线程安全的。静态变量除外(http://msdn.microsoft.com/en-us/library/system.management.automation.powershell%28VS.85%29.aspx)。
因此,尝试通过单独的线程调用多个脚本会导致内存泄漏和一些无法解释的CPU使用情况。我的猜测是它没有正确关闭。从多线程环境更改为多进程环境应该解决问题。然而,这意味着一场重大的政治变革。