Sprawdzanie procesów użytkownika - serwer

0

Dzień dobry.
Mam napisany mały programik, z którego w pewnym momencie uruchamiam inny program ERP i przekazuję pewne dane.
Zanim uruchomię ERP muszę sprawdzić czy już taki proces dla użytkownika istnieje. Mam kod który sprawdza czy proces jest uruchomiony i jaki użytkownik go uruchomił (poniżej).

            string value= "";
            Process[] allProc = Process.GetProcessesByName("ERP"); //Nazwa procesu 
            foreach (Process singleProc in allProc)
            {
                ObjectQuery query = new ObjectQuery("Select * From Win32_Process where ProcessId='" + singleProc.Id + "'");
                ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
                string processOwner = "";
                foreach (ManagementObject prc in searcher.Get())
                {
                    string[] arg = new string[2];
                    prc.InvokeMethod("GetOwner", (object[])arg);
                    processOwner = arg[1].ToString() + "\\"+arg[0].ToString();
                    break;
                }
                value += "ID: " + singleProc.Id + ", P: "+singleProc.ProcessName+", U: " + processOwner+ "\n";
            }
            MessageBox.Show(value);

Program działa na serwerze Win2016 zatem mamy tu max 30 użytkowników a co za tym idzie 30 procesów.
Gdy procesów ERP jest niewiele np 1-3 program działa to szybko, ale im więcej użytkowników odpali ERP tym dłużej trwa sprawdzanie procesów.
EDIT: Już przy 10 użytkownikach/procesach czas sprawdzania to 20 sek., a przy 28 rośnie do 1m 15 sek.
Czy jest jakiś sposób, żeby zoptymalizować ten kawałek kodu, tak żeby wykonywał się w miarę szybko dla wielu procesów ?

0

Możesz spróbować w foreach odpalić kilka wątków i w każdym sprawdzić tylko wybraną część tego, co Ci zwróciło zapytanie o procesy. Nie wiem, czy to da realny zysk, ale warto sprawdzić. A jeśli odczujesz różnice, to potem pobaw się/poeksperymentuj z ilościami wątków, do jakiej liczby jest odczuwalny wzrost wydajności. Bo niekoniecznie walnięcie 100 wątków spowoduje 100x wzrost prędkości ;)

Mógłbyś też napisać, co oznacza "dłuższe sprawdzanie" przy 10 userach. Czy chodzi o 2-3 sekundy, czy na pół minuty Ci się to blokuje?

0

Tak, urwałem zdanie, już poprawiłem.
EDIT: Już przy 10 użytkownikach/procesach czas sprawdzania to 20 sek., a przy 28 rośnie do 1m 15 sek.
Dzięki za podpowiedź. Spróbuję z wieloma wątkami. Zakładam, że było by świetnie gdyby udało się zejść poniżej 5 sek, bo cały ten mechanizm ma być dość często wykorzystywany.

0

cały ten mechanizm ma być dość często wykorzystywany

To możesz pomyśleć o czymś innym - odpalić jakąś usługę działającą w tle, która co kilka/kilkanaście sekund aktualizuje listę procesów. A Twoja aplikacja, podczas sprawdzania, nie będzie bezpośrednio sprawdzać wątków, tylko odpytywać tą usługę pośredniczącą. Ewentualnie, jeśli Twoja apka jest odpalana na jednym kompie i w jednej instancji, to zamiast osobnej usługi, możesz w jej ramach stworzyć specjalny wątek, który będzie cały czas śmigać w tle i którego zadaniem będzie aktualizowanie podręcznej listy procesów.

Plusy: dostajesz odpowiedź natychmiast
Minusy: ryzyko, że jeśli w ciągu ostatnich kilku(nastu) sekund, czyli od ostatniego sprawdzenia, coś się zmieniło - możesz dostać lekko nieaktualne dane.

0

Dokładnie z powodu WMI trochę się ślimaczącego mam podobny kod opakowane w klasę, która chowa P/Invoke i ułatwia wyciągnie danych użyszkodnika z pomocą Win32. To coś w tym stylu:
https://stackoverflow.com/questions/777548/how-do-i-determine-the-owner-of-a-process-in-c
(edit: poprawiłem link na lepszy przykład)

Tak odnośnie Twojego kodu (jeśli chcesz go trochę przyspieszyć małym wysiłkiem i kod ten jest wywoływany często), stworzy sobie jakiś cache z invalidation policy na np. zmianę listy tychże procesów. Od czasu do czasu (np. przed wykonaniem akcji na procesie) będziesz musiał sprawdzić czy pid wciąż należy do użytkownika, ale oszczędzi to ciągłego mielenia po WMI.

0

będziesz musiał sprawdzić czy pid wciąż należy do użytkownika

Akurat "zniknięcie" procesu łatwo wykryć, gorzej w sytuacji, jeśli proces się nagle pojawi, ale nasza klasa pośrednicząca jeszcze tego nie zauważyła.

1

Dziękuję za sugestie.
Popracowałem nad tym ale nadal był problem z wydajnością. Wygląda na to, że samo odpytywanie Win32 jest dość kosztowne.
Przy okazji dobrałem się od Process.GetCurrentProcess().SessionId i wyszedł dość banalny kod:

            int _f = 0;
            Process[] allProc = Process.GetProcessesByName("ERP"); //Nazwa procesu 
            foreach (Process singleProc in allProc)
            {
                if (singleProc.SessionId == Process.GetCurrentProcess().SessionId)
                {
                    _f = 1;
                }
            }
            if (_f == 1)
            {
                MessageBox.Show("Program już uruchomiony.");
            }
            else
            {
                MessageBox.Show("Uruchamiam program.");
            }

Sprawdzam po prostu sesję procesów z domyślną sesją, którą każdy zalogowany użytkownik teoretycznie powinien mieć inną.
Wygląda na to, że działa to bardzo szybko (poniżej 5 sek.), choć jakoś nie do końca jestem pewny czy gdzieś się coś nie wykrzaczy.
Wdzięczny będę za wszelkie uwagi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1