Как сделать поток членов C # Powershell Invoke безопасным - PullRequest
2 голосов
/ 25 августа 2010

У меня есть этот сервис, который при получении запроса запускает команду powershell и возвращает результат.Вот код класса invoker:

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;
    }
}

Метод Invoke возвращает все результаты, возвращаемые скриптом powershell.

Все хорошо и хорошо.Пока это работает в одном потоке.Поскольку некоторые сценарии PowerShell, которые мы вызываем, могут занять до часа, и мы не хотим, чтобы сервис ничего не делал в это время, мы решили использовать многопоточность.К сожалению, класс Powershell не является потокобезопасным, что приводит к серьезным утечкам памяти и скорости записи процессора.Однако, если я использую блокировку в методе Invoke, это будет означать, что вся идея, по которой мы пошли в многопоточном режиме, пойдет не так.

Ответы [ 2 ]

1 голос
/ 26 августа 2010

В любом случае ... Я отказался от многопоточности при выполнении команд powershell. Я создал небольшую программу, которая может выполнять сценарии PowerShell. Затем каждый поток создает новый процесс для этой программы. Я знаю, что это немного накладные расходы, но это работает.

По сути, классы Powershell не являются потокобезопасными. За исключением статических переменных (http://msdn.microsoft.com/en-us/library/system.management.automation.powershell%28VS.85%29.aspx).

Следовательно, попытка вызвать несколько сценариев через отдельные потоки приводит к утечке памяти и некоторому необъяснимому использованию процессора. Мое дикое предположение, что это не закрывается должным образом. Переход от многопоточной к многопроцессорной среде должен разобраться. Однако это означает серьезные изменения в политике.

1 голос
/ 25 августа 2010

Вы можете использовать BeginInvoke() метод класса PowerShell вместо Invoke(), который вы используете. В этом случае вы выполняете свой скрипт асинхронно и не блокируете вызывающий поток. Но вы также должны пересмотреть весь свой сценарий. Ваш старый синхронный метод возвращает результаты, которые можно легко использовать сразу после вызова. В новом асинхронном подходе это невозможно таким же образом.

см http://msdn.microsoft.com/en-us/library/system.management.automation.powershell.begininvoke

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...