2016-01-29 3 views
-2

Я сейчас переписываю приложение, которое я сделал некоторое время назад. Одной из функций, доступных пользователям, является перечислить все процессы, которые в настоящее время работают в активном сеансе 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», но это не повлияло, поэтому я решил это как возможность.

+1

Я не вижу существенных отличий в коде, ведущем к вызову 'WaitForExit()' и включая его. Даже выполняемый процесс один и тот же (вопреки тому, что вы указываете в своем повествовании). Фактически, единственное, что должно повлиять на время, которое требуется для возвращения WaitForExit(), - это то, как долго выполняется процесс, который вы выполняете. Вы должны начать с проверки того, что старый код также не замедлился; то есть что-то в вашей системе, заставляя команду 'tasklist' запускаться медленно, независимо. –

+1

Если у вас все еще есть проблемы и нужна помощь, пожалуйста, улучшите вопрос, предоставив пару хороших [mcve] s, которые надежно демонстрируют сценарии «медленный» и «не медленный». Что бы ни происходило, существует слишком много возможных объяснений для того, чтобы этот вопрос был полезен или по теме, как указано в настоящее время. –

+0

@PeterDuniho Большое спасибо за ваши полезные комментарии. После того, как вы ответили, я проверил это более тщательно и записал прошедшее время. Заметив, что новый метод был последовательно медленнее на 'WaitForExit(), я более пристально посмотрел и понял, что в старом методе я включал имя домена в запрос taslkist! То есть 'tasklist/S XA7-17.domain.co.uk', а не' tasklist/S XA7-17'. Поэтому я добавил доменное имя к запросам в новом методе, и это так же быстро! Я отправлю подробное расследование в качестве ответа, когда я получу шанс позже сегодня. Еще раз спасибо! – Bassie

ответ

1

Это связано с тем, что запрос не включает имя домена после имени сервера.

Я провел несколько тестов с использованием C# Секундомер класс, и кажется, что работает этот запрос:

TASKLIST /S XA7-17

намного медленнее, чем при запуске

TASKLIST /S XA7-17.domain.co.uk

После включения доменного имени в конце сервера мои запросы так же быстрые в старом приложении.