Python'da belirli bir pid ile bir işlem olup olmadığı nasıl kontrol edilir?


109

Bir pid'nin geçerli bir sürece karşılık gelip gelmediğini kontrol etmenin bir yolu var mı? Kaynak dışında farklı bir kaynaktan bir pid alıyorum os.getpid()ve bu pid ile bir işlemin makinede olup olmadığını kontrol etmem gerekiyor.

Unix ve Windows'ta bulunmasına ihtiyacım var. Ayrıca PID'nin kullanımda OLMADIĞINI kontrol ediyorum.


2
Windows standart olmayan bir işletim sistemidir. Bu tür şeyler taşınabilir DEĞİLDİR. İkisine birden sahip olamayacağınızı bilmek, önceliğiniz nedir? Öncelik olarak birini seçin ve soruyu düzenleyin.
S.Lott

26
S.Lott @ Windows'un standart dışı bir işletim sistemi olduğunu ... Bu benim SO üzerinde gördüğüm en saçma sözler biridir
Piotr Dobrogost

2
@Piotr Dobrogost: POSIX standart unix ve POSIX olmayan standart Windows'u işleyen bir kod sağlayabilir misiniz? Öyleyse, lütfen (a) sorunu çözen ve (b) Windows'un bir şekilde POSIX standardıyla uyumlu olduğunu açıkça belirten bir yanıt verin.
S.Lott

3
@PiotrDobrogost Sanırım S.Lott'un açıklaması, pazar payından çok uygulama ayrıntıları ve API desteği hakkındaydı.
Roy Tinker

3
Windows'un diğer popüler işletim sistemleriyle diğerlerinin birbirleriyle yaptığından kesinlikle daha az ortak noktası vardır. (Web geliştirme yapan herkes, onu benzer şekilde kötü şöhretli bir Microsoft ürününe benzetebilir.) Ancak @ S.Lott'a yanıt olarak: Linux, OSX, BSD vb. Üzerinde de çalışması gerekmeyen Windows için Python kodunu nadiren yazıyorum, bu yüzden ben dürüst olmak gerekirse, 'öncelik olarak seçmenin' yararlı bir tavsiye olduğunu düşünmeyin, özellikle de Python platform farklılıklarını mümkün olduğu kadar soyutladığından.
Michael Scheper

Yanıtlar:


163

0 sinyalini bir pid'e göndermek, pid çalışmıyorsa bir OSError istisnası ortaya çıkarır ve başka türlü bir şey yapmaz.

import os

def check_pid(pid):        
    """ Check For the existence of a unix pid. """
    try:
        os.kill(pid, 0)
    except OSError:
        return False
    else:
        return True

3
Linux ve OSX'te kesinlikle çalışıyor, Windows adına konuşamıyorum. İşlemi sorduğunuz anlamda sonlandırmaz, temelde "Koşuyor musunuz?" Olan 0 sinyalini gönderir.
mluebke

10
UNIX benzeri sinyaller diye bir şey olmadığından, bu kesinlikle Windows'ta çalışmaz.
Alexander Lebedev

13
Tamamlanması için, 3 olduğundan emin olmak için hata numarasını da kontrol etmelisiniz (istisnayı yakalayın ve ilk argümanı kontrol edin). Hedef süreç mevcutsa ancak sinyal gönderme izniniz yoksa (her ne sebeple olursa olsun) bu önemlidir.
haridsv

8
Artık Windows tarafından desteklenmektedir. docs.python.org/library/os.html?highlight=os.kill#os.kill
michael

15
os.kill, Windows'ta desteklenir, ancak işlemi sonlandırabilecek (veya başarısız olabileceği) ile os.kill(pid, 0)aynıdır os.kill(pid, signal.CTRL_C_EVENT). Bir olsun OSErrornerede errno==EINVALben bir alt süreç bu çalıştıklarında.
Jason R. Coombs

76

psutilModüle bir göz atın :

psutil (python sistemi ve işlem yardımcı programları), Python'da çalışan işlemler ve sistem kullanımı (CPU, bellek, diskler, ağ) hakkında bilgi almak için bir çapraz platform kitaplığıdır . [...] Şu anda hem 32-bit hem de 64-bit mimarileri olan Linux , Windows , OSX , FreeBSD ve Sun Solaris'i desteklemektedir ve Python sürümleri 2.6'dan 3.4'e kadardır (Python 2.4 ve 2.5 kullanıcıları 2.1.3 sürümünü kullanabilir) . PyPy'nin de çalıştığı bilinmektedir.

pid_exists()Verilen pid ile bir işlemin var olup olmadığını kontrol etmek için kullanabileceğiniz adında bir işlevi vardır.

İşte bir örnek:

import psutil
pid = 12345
if psutil.pid_exists(pid):
    print("a process with pid %d exists" % pid)
else:
    print("a process with pid %d does not exist" % pid)

Referans için:



Windows'ta pid_exists'in güvenilirliğini bıraktığı bir örneğim vardı. Ölü pidlerin kullanımda olduğunu yanlış bildirmekti. Bu, psutil modülünüzü zaman zaman güncel tutmanız için bir hatırlatmadır - özellikle işletim sistemi yükseltmeleri yaparken.
Damon Brodie

62

mluebke kodu% 100 doğru değil; kill () ayrıca EPERM'yi (erişim reddedildi) yükseltebilir, bu durumda bu açıkça bir sürecin var olduğu anlamına gelir. Bunun işe yaraması gerekiyor:

(Jason R. Coombs yorumlarına göre düzenlendi)

import errno
import os

def pid_exists(pid):
    """Check whether pid exists in the current process table.
    UNIX only.
    """
    if pid < 0:
        return False
    if pid == 0:
        # According to "man 2 kill" PID 0 refers to every process
        # in the process group of the calling process.
        # On certain systems 0 is a valid PID but we have no way
        # to know that in a portable fashion.
        raise ValueError('invalid PID 0')
    try:
        os.kill(pid, 0)
    except OSError as err:
        if err.errno == errno.ESRCH:
            # ESRCH == No such process
            return False
        elif err.errno == errno.EPERM:
            # EPERM clearly means there's a process to deny access to
            return True
        else:
            # According to "man 2 kill" possible error values are
            # (EINVAL, EPERM, ESRCH)
            raise
    else:
        return True

Pywin32, ctypes veya bir C genişletme modülü kullanmadığınız sürece bunu Windows'ta yapamazsınız. Harici bir kitaplığa bağlı olarak sorun yoksa, psutil'i kullanabilirsiniz :

>>> import psutil
>>> psutil.pid_exists(2353)
True

haridsv, testin e.errno! = 3 olması gerektiğini önerir; belki e.errno! = errno.ESRCH
Jason R. Coombs

Neden? ESRCH "böyle bir işlem yok" anlamına gelir.
Giampaolo Rodolà

2
Sağ. ESRCH "böyle bir işlem yok" anlamına geldiğinden, errno! = ESRCH, işlevin adına çok benzeyen "böyle bir işlem yok" veya "işlem yok" anlamına gelir. Özellikle EPERM'den bahsettiniz, ancak diğer olası hata kodları ne anlama geliyor? ESRCH yakından ilişkili görünürken, kontrolün amacı ile gevşek bir şekilde ilişkili olan bir hata kodunu seçmek yanlış görünmektedir.
Jason R. Coombs

Haklısın. Şimdi önerdiğiniz şeyi yansıtan kodu düzenledim.
Giampaolo Rodolà

python3'te os.kill () ProcessLookupError atar
martinkunev

19

İşleme "0 sinyali" gönderilmesini içeren yanıtlar, yalnızca söz konusu işlemin testi çalıştıran kullanıcıya ait olması durumunda işe yarayacaktır . Aksi takdirde , sistemde pid mevcut olsa bile izinlerOSError nedeniyle bir alacaksınız .

Bu sınırlamayı aşmak için /proc/<pid>var olup olmadığını kontrol edebilirsiniz :

import os

def is_running(pid):
    if os.path.isdir('/proc/{}'.format(pid)):
        return True
    return False

Açıkçası bu, yalnızca linux tabanlı sistemler için geçerlidir.


yanlış. PermissionErrorpid var demektir, pid yoksa alırsınız ProcessLookupError.
jfs

OSErrorYa errno bakarak aracılığıyla ya da daha fazla uzmanlaşmış alıcı aracılığıyla - reddedildi iznine bağlı diğerlerinden ayırt edilebilir PermissionError/ ProcessLookupErrorkaynaklanıyor istisnalar OSError. Ayrıca, işlem mevcutsa yalnızca izin hatasını alırsınız. Bu nedenle, örneğiniz Linux ve diğer bazı Unices üzerinde çalışan alternatif bir yöntemdir, ancak düzgün bir şekilde çağırmaktan daha eksiksiz değildir os.kill(pid, 0).
maxschlepzig

Bu çözüm, corss-platform değildir. OP, Unix ve Windows'ta mevcut olmasını istiyor. /procProcfs sadece bile BSD veya OSX'te, Linux üzerinde çıkar.
Charles

/ Proc hidepid = 2 olarak bağlanırsa bu yöntem başarısız olur, işlem başka bir kullanıcıya aitse listede gösterilmez.
Perkins

8

Python 3.3+ sürümünde, errno sabitleri yerine istisna adları kullanabilirsiniz. Posix sürümü :

import os

def pid_exists(pid): 
    if pid < 0: return False #NOTE: pid == 0 returns True
    try:
        os.kill(pid, 0) 
    except ProcessLookupError: # errno.ESRCH
        return False # No such process
    except PermissionError: # errno.EPERM
        return True # Operation not permitted (i.e., process exists)
    else:
        return True # no error, we can send a signal to the process

7

Bakın burada kendi kimlikleri ile çalışan işlem tam listesini alma pencereleri özgü yol. Gibi bir şey olurdu

from win32com.client import GetObject
def get_proclist():
    WMI = GetObject('winmgmts:')
    processes = WMI.InstancesOf('Win32_Process')
    return [process.Properties_('ProcessID').Value for process in processes]

Daha sonra bu listeye karşı aldığınız pid'i doğrulayabilirsiniz. Performans maliyeti hakkında hiçbir fikrim yok, bu yüzden sık sık pid doğrulaması yapacaksanız bunu kontrol etseniz iyi olur.

* NIx için mluebke'nin çözümünü kullanın.


Bu benim için iyi çalıştı. Bir işlem adı olup olmadığını kontrol etmek istedim, böylece "İşlem Kimliği" "Ad" ile değiştirildi ve ayrıca bunu Doğru veya Yanlış döndürmek için bir kontrol listesine dönüştürdüm.
JamesR

6

Ntrrgc'leri temel alarak Windows sürümünü güçlendirdim, böylece işlem çıkış kodunu kontrol eder ve izinleri kontrol eder:

def pid_exists(pid):
    """Check whether pid exists in the current process table."""
    if os.name == 'posix':
        import errno
        if pid < 0:
            return False
        try:
            os.kill(pid, 0)
        except OSError as e:
            return e.errno == errno.EPERM
        else:
            return True
    else:
        import ctypes
        kernel32 = ctypes.windll.kernel32
        HANDLE = ctypes.c_void_p
        DWORD = ctypes.c_ulong
        LPDWORD = ctypes.POINTER(DWORD)
        class ExitCodeProcess(ctypes.Structure):
            _fields_ = [ ('hProcess', HANDLE),
                ('lpExitCode', LPDWORD)]

        SYNCHRONIZE = 0x100000
        process = kernel32.OpenProcess(SYNCHRONIZE, 0, pid)
        if not process:
            return False

        ec = ExitCodeProcess()
        out = kernel32.GetExitCodeProcess(process, ctypes.byref(ec))
        if not out:
            err = kernel32.GetLastError()
            if kernel32.GetLastError() == 5:
                # Access is denied.
                logging.warning("Access is denied to get pid info.")
            kernel32.CloseHandle(process)
            return False
        elif bool(ec.lpExitCode):
            # print ec.lpExitCode.contents
            # There is an exist code, it quit
            kernel32.CloseHandle(process)
            return False
        # No exit code, it's running.
        kernel32.CloseHandle(process)
        return True

Aslında göre msdn.microsoft.com/en-us/library/windows/desktop/... , GetExistCodeProcessgerektirir PROCESS_QUERY_INFORMATIONve PROCESS_QUERY_LIMITED_INFORMATIONerişim haklarını.
augustomen

Kodun yanlış olduğunu unutmayın. GetExitCodeProcessbir tutamaç ve bir işaretçi alır ve bu örnekte ExitCodeProcess, yalnızca bir işaretçi olması gerektiğinde ikinci parametre olarak bir yapı alır.
Fabio Zadrozny

OpenProcess'ten sonra GetLastError'ı kontrol etmek iyi bir fikirdir. ERROR_ACCESS_DENIED, işlemin var olduğu anlamına gelir! İşte bunu kullanan eksiksiz bir örnek: gist.github.com/ociule/8a48d2a6b15f49258a87b5f55be29250
ociule

4

Giampaolo Rodolà'nın POSIX cevabını ve Windows için benimkini birleştirerek şunu anladım:

import os
if os.name == 'posix':
    def pid_exists(pid):
        """Check whether pid exists in the current process table."""
        import errno
        if pid < 0:
            return False
        try:
            os.kill(pid, 0)
        except OSError as e:
            return e.errno == errno.EPERM
        else:
            return True
else:
    def pid_exists(pid):
        import ctypes
        kernel32 = ctypes.windll.kernel32
        SYNCHRONIZE = 0x100000

        process = kernel32.OpenProcess(SYNCHRONIZE, 0, pid)
        if process != 0:
            kernel32.CloseHandle(process)
            return True
        else:
            return False

Windows sürümü benim için Windows 8.1'de çalışmıyor. Kontrol etmeli GetExitCodeProcessve erişiminiz olduğundan emin olmalısınız.
sürat uçağı

kernel32.OpenProcessSadece kullanmak yeterli değildir. Gibi burada işaret "süreci son zamanlarda çıkıldı bile, bir pid hala sap için var olabilir." Eğer kernel32.OpenProcessdöner sıfır dışında bir değere, hala ihtiyaç kernel32.GetExitCodeProcessçıkış kodunu kontrol etmek daha da.
Miyav

2

Windows'ta bunu şu şekilde yapabilirsiniz:

import ctypes
PROCESS_QUERY_INFROMATION = 0x1000
def checkPid(pid):
    processHandle = ctypes.windll.kernel32.OpenProcess(PROCESS_QUERY_INFROMATION, 0,pid)
    if processHandle == 0:
        return False
    else:
        ctypes.windll.kernel32.CloseHandle(processHandle)
    return True

Öncelikle bu kodda verilen pid ile işlem için bir tutamaç elde etmeye çalışıyorsunuz. Tanıtıcı geçerliyse, işlem için tanıtıcıyı kapatın ve True döndür; aksi takdirde False döndürürsünüz. OpenProcess için Belgeler: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684320%28v=vs.85%29.aspx


2

Bu, Linux için çalışacaktır, örneğin banshee'nin çalışıp çalışmadığını kontrol etmek istiyorsanız ... (banshee bir müzik çalar)

import subprocess

def running_process(process):
    "check if process is running. < process > is the name of the process."

    proc = subprocess.Popen(["if pgrep " + process + " >/dev/null 2>&1; then echo 'True'; else echo 'False'; fi"], stdout=subprocess.PIPE, shell=True)

    (Process_Existance, err) = proc.communicate()
    return Process_Existance

# use the function
print running_process("banshee")

Bu yöntem, kullanmaya os.kill(pid, 0)veya bakmaya kıyasla açıkça daha düşüktür /proc/{pid}. Bir sistem çağrısı yürütmek yerine, kodunuz bir çocuğu çatallar, o çocukta bir kabuk çalıştırır, kabuk gereksiz mini kabuk betiğinizi yorumlar, kabuk, pgrep'i çalıştıran başka bir çocuğu çatallar ve sonunda pgrep yineler /proc. Cevabınız gönderilen soruya cevap vermiyor. OP, PID verilen bir yöntem istedi. Yönteminiz bir işlem adı gerektiriyor.
maxschlepzig

0

Aşağıdaki kod hem Linux hem de Windows üzerinde çalışır ve harici modüllere bağlı değildir

import os
import subprocess
import platform
import re

def pid_alive(pid:int):
    """ Check For whether a pid is alive """


    system = platform.uname().system
    if re.search('Linux', system, re.IGNORECASE):
        try:
            os.kill(pid, 0)
        except OSError:
            return False
        else:
            return True
    elif re.search('Windows', system, re.IGNORECASE):
        out = subprocess.check_output(["tasklist","/fi",f"PID eq {pid}"]).strip()
        # b'INFO: No tasks are running which match the specified criteria.'

        if re.search(b'No tasks', out, re.IGNORECASE):
            return False
        else:
            return True
    else:
        raise RuntimeError(f"unsupported system={system}")

İhtiyaç duymanız durumunda kolayca geliştirilebilir

  1. diğer platformlar
  2. diğer dil

-2

PID'yi hangi amaçla elde ediyorsanız kullanın ve hataları nazikçe halledin derim. Aksi takdirde, bu klasik bir yarış (PID geçerli olduğunu kontrol ettiğinizde geçerli olabilir, ancak bir an sonra kaybolur)


Daha spesifik olmalıydım - GEÇERSİZLİĞİ kontrol ediyorum. Bu yüzden, temelde bir pid'in kullanımda OLMADIĞINI görmek istiyorum.
Evan Fosmark

1
Ama bu cevabı ne yapacaksın? Bu bilgiyi kazandıktan hemen sonra, bir şey o pidi kullanabilir.
Damien_The_Unbeliever

@Damien_The_Unbeliever - bu bilgiyi edindikten sonra bir şey onu kullanıyorsa sorun değil ve yarış durumu hakkında ne söylediğini anlıyorum, ancak bunun benim durumum için geçerli olmadığını garanti edebilirim.
Evan Fosmark
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.