C# 管道能否在同一运行空间中并发运行?

C# 管道能否在同一运行空间中并发运行?,c#,powershell,C#,Powershell,如何在同一运行空间中并行运行两个cmdlet。我用的是C# 在两个线程中,我将使用相同的运行空间运行cmdlet Pipeline pipeLine = powerShellRunspace.CreatePipeline(); pipeLine.Commands.Add(shellCommand); pipeLine.Input.Close(); pipeLine.Invoke(); pipeLine.Output.DataReady += new EventHandler(processDat

如何在同一运行空间中并行运行两个cmdlet。我用的是C#

在两个线程中,我将使用相同的运行空间运行cmdlet

Pipeline pipeLine = powerShellRunspace.CreatePipeline();
pipeLine.Commands.Add(shellCommand);
pipeLine.Input.Close();
pipeLine.Invoke();
pipeLine.Output.DataReady += new EventHandler(processData);    //processData is a method which processes data emitted by pipeline as and when it comes to avoid out of memory
if (pipeLine.Error != null && pipeLine.Error.Count > 0) {
    Collection<Object> errors = (Collection<Object>)(pipeLine.Error.ReadToEnd());
    //process those errors
}
Pipeline-Pipeline=powerShellRunspace.CreatePipeline();
pipeLine.Commands.Add(shell命令);
pipeLine.Input.Close();
pipeLine.Invoke();
pipeLine.Output.DataReady+=新的EventHandler(processData)//processData是一种处理管道发出的数据以避免内存不足的方法
if(pipeLine.Error!=null&&pipeLine.Error.Count>0){
集合错误=(集合)(pipeLine.Error.ReadToEnd());
//处理这些错误
}
但是当两个线程同时使用相同的运行空间来运行cmdlet时。我得到一个异常,“管道未执行,因为管道已经在执行。管道不能并发执行。”

出于性能原因,我需要使用相同的运行空间。如何实现我的目标?

你看过这门课了吗?使用它和InitialSessionState可以帮助消除模块导入的开销,因为它只在每个池而不是每个运行空间中执行一次。如果您正在寻找powershell命令的异步执行,这里有一个非常基本的、不适合生产的示例:(注意,我不是在使用Visual Studio的计算机上,但这应该是正确的)


运行空间缺少支持并发性所需的同步。假设您的目标是“良好的性能”,您应该进一步说明为什么多个运行空间不能给您带来良好的性能。您好@JasonShirk,我的是web应用程序,因为我正在运行空间中导入powershell模块,当许多用户发出http请求时,速度会很慢。您知道如何在Runspacepool中进行错误处理吗?我必须绑定eventhandler以避免内存不足(更新了我的代码)…我遇到了同样的问题。有人尝试过这些解决方案并成功了吗@Praveen KumarHi@ch.smrutiranjanparida,我想我使用RunspacePool并将该池分配给PowerShell obj,使用powerShellObj.Streams.Error进行错误处理,并使用powerShellObj.BeginInvoke将PSDataCollection传递给它,以处理PowerShell commandHi@StephenP发出的数据,但是如何在使用RunspacePool时处理错误,我已经更新了我的代码,以展示如何在使用单个运行空间时处理错误。需要注意的是,我的是web应用程序,所以我不能同时异步运行所有powershell命令,powershell命令将在http请求发出时运行。在调用powershell命令之前,我应该绑定
pipeLine.Output.DataReady+=new EventHandler(processData)
处理管道发出的数据,以避免内存不足。在进行EndInvoke调用时,powershell命令引发的错误将作为运行时错误被拾取。您需要添加错误处理逻辑。您还可以检查和属性。您仍然可以使用runspacepool来消除模块导入的一些开销,您只需要实现runspacepool的缓存。@StephenP我认为您不能在迭代字典时修改它。应该将toBeRemoved添加到要删除的项集合中,然后从foreach循环之外的字典中删除该集合中的每个项(sleep语句所在的位置)。否则我很肯定你会得到一个例外。@ksun接得好。我把}放错地方了。if(toBeRemoved)应该在foreach循环之后。我在thread.sleep调用之前有一个},而不是if(toBeRemoved)。我已经更新了答案。
Pipeline pipeLine = powerShellRunspace.CreatePipeline();
pipeLine.Commands.Add(shellCommand);
pipeLine.Input.Close();
pipeLine.Invoke();
pipeLine.Output.DataReady += new EventHandler(processData);    //processData is a method which processes data emitted by pipeline as and when it comes to avoid out of memory
if (pipeLine.Error != null && pipeLine.Error.Count > 0) {
    Collection<Object> errors = (Collection<Object>)(pipeLine.Error.ReadToEnd());
    //process those errors
}
InitialSessionState iss = InitialSessionState.CreateDefault();
iss.AuthorizationManager = new AuthorizationManager("MyShellId");
iss.ImportPSModule(new string[] { "MSOnline" });
#set commands we want to run concurrently
string[] commands = new string[4] {
    "Start-Sleep -Seconds 5; 'Hi from #1'",
    "Start-Sleep -Seconds 7; 'Hi from #2'",
    "Start-Sleep -Seconds 3; 'Hi from #3'",
    "throw 'Danger Will Robinson'"
};
Dictionary<PowerShell, IAsyncResult> dict = new Dictionary<PowerShell, IAsyncResult>();
//this loads the InitialStateSession for all instances
//Note you can set the minimum and maximum number of runspaces as well
using(RunspacePool rsp = RunspaceFactory.CreateRunspacePool(iss))
{
    rsp.SetMinRunspaces(5);
    rsp.SetMaxRunspaces(10);
    rsp.Open();
    foreach(string cmd in commands)
    {
        PowerShell ps = PowerShell.Create();
        ps.AddScript(cmd);
        ps.RunspacePool = rsp;
        //Add parameters if needed with ps.AddParameter or ps.AddArgument
        dict.Add(ps,ps.BeginInvoke());            
    }
    do{
        List<PowerShell> toBeRemoved = new List<PowerShell>();
        foreach(KeyValuePair<PowerShell, IAsyncResult> kvp in dict)
        {
            if(kvp.Value.IsCompleted)
            {
                try
                {
                    PSDataCollection<PSObject> objs = kvp.Key.EndInvoke(kvp.Value);
                    foreach(PSObject obj in objs)
                    {
                        Console.WriteLine(obj);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine(e);
                }
                finally
                {
                    toBeRemoved.Add(kvp.Key);
                }
            }
        }
        foreach(PowerShell item in toBeRemoved)
        {
            dict.Remove(item);
        }
        //Wait before we check again
        Thread.Sleep(200);
    } while (dict.Count > 0)
    rsp.Close();
}
//Added to keep console open
Console.Read();
Hi from #3
Hi from #1
Hi from #2