Process.WaitForExit() намного медленнее после рефакторинга при вызове Taskkill
Я нахожусь в процессе переписывания заявления, которое я сделал некоторое время назад. Одной из функций, доступных пользователям, является перечисление всех процессов, которые в данный момент выполняются в активном сеансе Citrix, и их отображение (аналог Windows Task Manager). Проблема в том, что при запросе tasklist
на компьютере пользователя, а также время, необходимое для вывода результатов этой команды.
Моя новая версия кода использует гораздо более объектно-ориентированный подход с использованием нестатических классов для представления 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", но это никак не повлияло, поэтому я исключил это как возможность.
1 ответ
Это было связано с тем, что запрос не включал доменное имя после имени сервера.
Я провел несколько тестов, используя класс C# Stopwatch, и кажется, что этот запрос выполняется:
TASKLIST /S XA7-17
Намного медленнее, чем бег
TASKLIST /S XA7-17.domain.co.uk
После включения доменного имени в конце сервера мои запросы выполняются так же быстро, как и в старом приложении.