Prozess-IDs (PIDs) laufender Prozesse ermitteln

Code-Stücke können hier veröffentlicht werden.
Antworten
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hi!

Das Problem ist, dass die Ermittlung der PIDs plattformabhängig ist. Deshalb habe ich mir mal einen kleinen Prototypen zusammengestellt.

Code: Alles auswählen

---Der Code wurde verbessert. Siehe weiter unten.---
Für Ideen und Erweiterungen um andere Plattformen bin ich offen und werde diese natürlich einbauen.

Siehe auch: http://www.python-forum.de/topic-8915.html

lg
Gerold
:-)
Zuletzt geändert von gerold am Freitag 19. Januar 2007, 15:11, insgesamt 3-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Super. Das kann man immer mal gebrauchen 8)

lg
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Und warum steht sowas nicht im Wiki? :roll:
TUFKAB – the user formerly known as blackbird
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hi!

Ich habe den Code für Windows ein wenig verfeinert.
Wenn ``pywin32`` nicht installiert ist, dann wird geprüft ob ``ctypes`` installiert ist. Wenn ja, dann wird direkt auf die ``psapi.dll`` zugegriffen. Ab Python 2.5 ist ``ctypes`` mit dabei. Deshalb glaube ich, dass das keine so schlechte Lösung ist. Bis es so weit ist, gibt es noch den Fallback über die ``tasklist.exe``. Das Programm ``tasklist.exe`` ist allerdings erst ab Windows XP mit dabei. Deshalb wird die Exception ``NotImplementedError`` ausgelöst, wenn die ProzessIDs damit nicht ermittelt werden konnten.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-

import sys
import os


def get_current_pids():
    """
    Returns current process-id's.
    
    :return: List with process-id's.
    """
    
    if sys.platform.startswith("win"):
        # Windows
        try:
            import win32process
            # pywin32 is installed --> EnumProcesses
            return list(win32process.EnumProcesses())
        except ImportError:
            try:
                import ctypes as ct
                # ctypes is installed --> try psapi.dll
                psapi = ct.windll.psapi
                arr = ct.c_long * 1024
                process_ids = arr()
                cb = ct.sizeof(process_ids)
                bytes_returned = ct.c_ulong()
                psapi.EnumProcesses(ct.byref(process_ids), cb, ct.byref(bytes_returned))
                return sorted(list(set(process_ids)))
            except ImportError:
                # pywin32 and ctypes are not installed --> tasklist.exe
                # runs on Windows XP and higher.
                import csv
                csvlines = []
                current_pids = []
                for line in os.popen("tasklist.exe /fo csv /nh"):
                    line = line.strip()
                    if line:
                        csvlines.append(line)
                for line in csv.reader(csvlines):
                    current_pids.append(int(line[1]))
                if not current_pids:
                    raise NotImplementedError("tasklist.exe not found (>WinXP)")
                return current_pids
    else:
        # Linux, Cygwin
        current_pids = []
        for filename in os.listdir("/proc"):
            if os.path.isdir(os.path.join("/proc", filename)):
                try:
                    current_pids.append(int(filename))
                except ValueError:
                    pass
        return current_pids


def main():
    """Testing"""
    current_pids = get_current_pids()
    print current_pids
    print "Count:", len(current_pids)


if __name__ == "__main__":
    main()
Wie würde man in anderen Betriebssystemen vorgehen um die PIDs zu ermitteln?

lg
Gerold
:-)
Zuletzt geändert von gerold am Montag 15. Januar 2007, 22:53, insgesamt 1-mal geändert.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
sape
User
Beiträge: 1157
Registriert: Sonntag 3. September 2006, 12:52

Wow, sehr Cool 8) Du hast ja wirklich an alles gedacht.
Gerold, ich wäre auch dafür das dass ins Wiki kommt.

lg
sape
oliver1974
User
Beiträge: 97
Registriert: Donnerstag 26. Oktober 2006, 15:01

Hab hier noch eine kleine Änderung, die den
"posix" Zweig (Linux, BSD, MacOSX) betrifft:

Das Problem hierbei ist, das "/proc" nicht auf allen POSIX-Systemen
zur Verfügung steht, wie man etwa vermuten würde...

MacOSX hat das Verzeichnis nicht, das hat man entsprechend
von den BSD - Betriebssystemen übernommen, die es wohl
nur noch zur Abwärtskompatibilität haben, wenn überhaupt
(was wohl nicht garantiert ist, so genau kenne ich mich
jetzt mit den BSD-Derivaten nicht aus.)

Ich würde hier ganz einfach die Rückgabewerte des
Shell Befehls "ps a" auswerten.. Dieser liefert die Prozesse
aller Nutzer (Das ist die Option "a".. ja, tatsächlich ohne führenden
Bindestrich hier, das ist nämlich der "BSD-Style" und der geht
sowohl unter Linux als auch BSD/MacOSX).

EDIT: Die hinzugefügte Funktion do_command
ist nur dazu gedacht, um für die neueren Python
Versionen, die Ausführung der Shell-Kommandos
via "subprocess" zu ermöglichen, während die älteren
die alte "os.popen" Methode weiter benutzen...
(Ist also für diejenigen, die es ganz genau nehmen.. ;-) )

Code: Alles auswählen

def do_command(command):
    """
    Führt ein Shell-Kommando aus, je nach Python-Version in
    der "richtigen" Art und Weise.
    :return: Liste mit den Zeilen der Ausgabe des Shell-Kommandos.
    """
    try:
        # Für Python ab 2.4
        from subprocess import Popen, PIPE
        p1 = Popen(command, stdout=PIPE, shell=True)
        output = p1.communicate()[0]
        lines = output.split("\n")
    except ImportError:
        # Ältere Python Versionen
        p1 = os.popen(command, 'r')
        lines = p1.readlines()
    
    return lines


def get_current_pids():
    """
    Liefert die aktuellen Prozess-IDs.
    Funktioniert mit Windows 32-Bit Versionen (64-Bit nicht getestet,
    sollte aber funktionieren), Linux, MacOSX.
    Sollte auch mit diversen BSD-Varianten funktionieren, aber noch nicht
    getestet.
    
    :return: Liste mit den Prozess-IDs
    """
   
    if sys.platform.startswith("win"):
        # Windows
        try:
            import win32process
            # pywin32 ist installiert --> EnumProcesses
            return list(win32process.EnumProcesses())
        except ImportError:
            try:
                import ctypes as ct
                # ctypes ist installiert --> Probiere mit psapi.dll
                psapi = ct.windll.psapi
                arr = ct.c_long * 1024
                process_ids = arr()
                cb = ct.sizeof(process_ids)
                bytes_returned = ct.c_ulong()
                psapi.EnumProcesses(ct.byref(process_ids), cb, 
                                    ct.byref(bytes_returned))
                return sorted(list(set(process_ids)))
            except ImportError:
                # pywin32 und ctypes sind nicht installiert --> tasklist.exe
                # Läuft mit Windows XP und höher.
                import csv
                csvlines = []
                current_pids = []
                for line in do_command("tasklist.exe /fo csv /nh"):
                    line = line.strip()
                    if line:
                        csvlines.append(line)
                for line in csv.reader(csvlines):
                    current_pids.append(int(line[1]))
                if not current_pids:
                    raise NotImplementedError("tasklist.exe not found (>WinXP)")
                return current_pids
    else:
        # Linux, Cygwin, BSD-Varianten, MacOSX
        # Wir fragen hier nicht etwa das "/proc" Verzeichnis
        # ab, was unter Linux gehen würde, aber nicht unter den
        # BSD - Systemen (wie MacOSX), sondern wir lesen einfach
        # die Ausgabe des Befehls "ps a" aus.
        current_pids = []
        command = 'ps a'
        lines = do_command(command)
        
        # Überspringe erste Zeile, die die Header-Zeile ist
        for line in lines[1:]:
            line = line.strip()
            if line != "":
                pid = line.strip().split(" ")[0]                                
                try:
                    current_pids.append(int(pid))
                except ValueError:
                    pass
        
        return current_pids
Antworten