Я сейчас переписываю приложение, которое я сделал некоторое время назад. Одной из функций, доступных пользователям, является перечислить все процессы, которые в настоящее время работают в активном сеансе Citrix, и отображать их (аналогичный диспетчер задач Windows). Проблема заключается в том, что при запросе tasklist
на машине пользователя и длительности времени для вывода результатов этой команды.Process.WaitForExit() намного медленнее после рефакторинга при вызове Taskkill
Моя новая версия кода использует гораздо более объектно-ориентированный подход, используя нестатические классы для представления Sessions
и Procs
(Процессы).
Исходный код выглядел так, и она работала достаточно хорошо с точки зрения продолжительности времени, на самом деле выполнения запроса и получения выходных результатов:
СТАРЫЙ КОД:
public static Dictionary<string, string> GetProcs(string server, string sessID)
{
SecureString ss = CreatePW();
ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/C tasklist /S " + server + " /FI \"SESSION eq " + sessID + "\" /FO CSV /NH")
{
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
WorkingDirectory = @"C:\windows\system32",
Verb = "runas",
Domain = "BARDOM1",
UserName = "zzkillcitrix",
Password = ss
};
List<string> procList = new List<string>();
Process proc = Process.Start(startInfo);
proc.OutputDataReceived += (x, y) => procList.Add(y.Data);
proc.BeginOutputReadLine();
proc.WaitForExit();
// Create a new ditionary ...
Dictionary<string, string> procDict = new Dictionary<string, string>();
for (int i = 0; i < procList.Count - 1; i++)
{
if (procDict.ContainsKey(procList[i].Split(',')[0].Trim('"')))
{
// Do nothing
}
else
{
procDict.Add(procList[i].Split(',')[0].Trim('"'), procList[i].Split(',')[1].Trim('"'));
}
}
return procDict;
}
Все это приложение очень беспорядочно, поэтому я переписал большую часть его, но моя единственная проблема заключается в том, что новый метод для извлечения текущего списка процессов намного медленнее (вероятно, примерно в 4-5 раз медленнее старой).
НОВЫЙ КОД:
В ProcessHelper классе
public static List<Proc> GetProcList(Session session)
{
// Get the current tasks
List<string> processQueryResult = TaskList(session);
List<Proc> procList = new List<Proc>();
foreach (var processDetails in processQueryResult)
{
// Only create the Proc if the process is in the 'valid' array ...
// Get the procname
string procName = processDetails.Split(',')[0].Trim('"').ToUpper();
// Make sure it's position is not -1 ...
int pos = Array.IndexOf(MyGlobals.ProcArray, procName);
if (pos > -1)
{
int procId = Int32.Parse(processDetails.Split(',')[1].Trim('"'));
Proc p = new Proc(procName, procId, session.ServerName, session.ID);
procList.Add(p);
SupportMI.Trace = "--adding" + p.Name + "--";
}
}
return procList;
}
private static List<string> TaskList(Session session)
{
string cmdIn = "tasklist /S " + session.ServerName + " /FI \"SESSION eq " + session.ID + "\" /FO CSV /NH";
List<string> cmdOut = Cmd.StdOutAdminList(cmdIn);
return cmdOut;
}
В классе Cmd
public static List<string> StdOutAdminList(string args)
{
List<string> cmdOut = new List<string>();
SecureString ss = pw();
ProcessStartInfo startInfo = new ProcessStartInfo("cmd", "/C " + args)
{
WindowStyle = ProcessWindowStyle.Hidden,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
WorkingDirectory = @"C:\windows\system32",
Verb = "runas",
Domain = "BARDOM1",
UserName = "zzkillcitrix",
Password = ss
};
cmdOut = ExecuteListCommand(startInfo);
return cmdOut;
}
private static List<string> ExecuteListCommand(ProcessStartInfo startInfo)
{
List<string> procList = new List<string>();
Process p = Process.Start(startInfo);
p.OutputDataReceived += (x, y) => procList.Add(y.Data);
p.BeginOutputReadLine();
p.WaitForExit();
return procList;
}
Возможные причины
В новой версии программы я также представил несколько новых объектов (например, класс Session и класс Proc для хранения информации об отдельных процессах). Возможно ли, что добавление этих дополнительных классов замедляет метод Process.WaitForExit()?
После некоторой отладки, кажется, что точка, в которой программа замедляется относительно старого кода, - это когда вызывается Process.WaitForExit()
- Что-нибудь влияет на этот вызов метода, кроме деталей ProcessStartInfo? если нет, то я очень смущен, так как я устанавливаю ProcessStarInfos на те же настройки, но все же новый код имеет задержку.
Еще одна мысль, которую я обнаружил, заключается в том, что, возможно, добавление большего количества объектов, что означает большее количество передаваемых параметров, замедляет работу всего приложения, которое каким-то образом проявляется так, как описано выше.
Любое понимание того, почему это может произойти, очень ценится. Пожалуйста, дайте мне знать, могу ли я предоставить более подробную информацию или код или выполнить любые тесты.
Я также назвал «список задач» непосредственно из Process
, а не «cmd», но это не повлияло, поэтому я решил это как возможность.
Я не вижу существенных отличий в коде, ведущем к вызову 'WaitForExit()' и включая его. Даже выполняемый процесс один и тот же (вопреки тому, что вы указываете в своем повествовании). Фактически, единственное, что должно повлиять на время, которое требуется для возвращения WaitForExit(), - это то, как долго выполняется процесс, который вы выполняете. Вы должны начать с проверки того, что старый код также не замедлился; то есть что-то в вашей системе, заставляя команду 'tasklist' запускаться медленно, независимо. –
Если у вас все еще есть проблемы и нужна помощь, пожалуйста, улучшите вопрос, предоставив пару хороших [mcve] s, которые надежно демонстрируют сценарии «медленный» и «не медленный». Что бы ни происходило, существует слишком много возможных объяснений для того, чтобы этот вопрос был полезен или по теме, как указано в настоящее время. –
@PeterDuniho Большое спасибо за ваши полезные комментарии. После того, как вы ответили, я проверил это более тщательно и записал прошедшее время. Заметив, что новый метод был последовательно медленнее на 'WaitForExit(), я более пристально посмотрел и понял, что в старом методе я включал имя домена в запрос taslkist! То есть 'tasklist/S XA7-17.domain.co.uk', а не' tasklist/S XA7-17'. Поэтому я добавил доменное имя к запросам в новом методе, и это так же быстро! Я отправлю подробное расследование в качестве ответа, когда я получу шанс позже сегодня. Еще раз спасибо! – Bassie