Рубрики
Без рубрики

Как найти и перечислить все беговые процессы с Python

Получите практические, реальные навыки Python на наших ресурсах и пути

Автор оригинала: Mike Driscoll.

На днях я был поручено найти способ получить список всех беговых процессов на виртуальной машине Windows XP. Я также должен был включить информацию о том, сколько процессора и памяти используются каждый процесс. К счастью, это не должно быть удаленным скриптом, но тот, который мог бы работать на клиенте. После справедливого погубинка здесь и там я наконец нашел решение. В этой статье мы рассмотрим некоторые из отклонений, а также в результате возможного решения, которое происходит с трудовой платформой.

Один из первых скриптов, которые я нашел, был Это один назад с марта 2006 года:

# http://mail.python.org/pipermail/python-win32/2006-March/004340.html
import win32com.client
wmi=win32com.client.GetObject('winmgmts:')
for p in wmi.InstancesOf('win32_process'):
    print p.Name, p.Properties_('ProcessId'), \
        int(p.Properties_('UserModeTime').Value)+int(p.Properties_('KernelModeTime').Value)
    children=wmi.ExecQuery('Select * from win32_process where ParentProcessId=%s' %p.Properties_('ProcessId'))
    for child in children:
        print '\t',child.Name,child.Properties_('ProcessId'), \
            int(child.Properties_('UserModeTime').Value)+int(child.Properties_('KernelModeTime').Value)

Этот скрипт требует от Pywin32 пакет работать. Однако, хотя это удобный маленький скрипт, он не показывает ничего, что я хочу, кроме процедуры. Я не забочусь о времени режима пользователя или ядра (I.e. Общее время процессора пользователем или ядром). Также я не очень люблю работать с черной магией ком, поэтому я закончил отказаться от этого из-за рук.

Далее был Активенский рецепт Отказ Это выглядело перспективным:

# http://code.activestate.com/recipes/303339-getting-process-information-on-windows/
import win32pdh, string, win32api

def procids():
    #each instance is a process, you can have multiple processes w/same name
    junk, instances = win32pdh.EnumObjectItems(None,None,'process', win32pdh.PERF_DETAIL_WIZARD)
    proc_ids=[]
    proc_dict={}
    for instance in instances:
        if instance in proc_dict:
            proc_dict[instance] = proc_dict[instance] + 1
        else:
            proc_dict[instance]=0
    for instance, max_instances in proc_dict.items():
        for inum in xrange(max_instances+1):
            hq = win32pdh.OpenQuery() # initializes the query handle 
            path = win32pdh.MakeCounterPath( (None,'process',instance, None, inum,'ID Process') )
            counter_handle=win32pdh.AddCounter(hq, path) 
            win32pdh.CollectQueryData(hq) #collects data for the counter 
            type, val = win32pdh.GetFormattedCounterValue(counter_handle, win32pdh.PDH_FMT_LONG)
            proc_ids.append((instance,str(val)))
            win32pdh.CloseQuery(hq) 

    proc_ids.sort()
    return proc_ids

print procids()

Увы, хотя это также получило список процессов из моего окна Windows (наряду с PID), оно не дало мне никакой информации о процессоре и использовании памяти. Я думаю, что это может работать, если бы я использовал разные имена контра. Я предполагаю, что если вы хотите, вы можете понять, что информация с использованием MSDN. Я не хотел связываться с этим, поэтому я продолжал копать.

Этот рецепт привел меня к следующему на базе CTYPES:

# http://code.activestate.com/recipes/305279/

"""
Enumerates active processes as seen under windows Task Manager on Win NT/2k/XP using PSAPI.dll
(new api for processes) and using ctypes.Use it as you please.

Based on information from http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q175030&ID=KB;EN-US;Q175030

By Eric Koome
email ekoome@yahoo.com
license GPL
"""
from ctypes import *

#PSAPI.DLL
psapi = windll.psapi
#Kernel32.DLL
kernel = windll.kernel32

def EnumProcesses():
    arr = c_ulong * 256
    lpidProcess= arr()
    cb = sizeof(lpidProcess)
    cbNeeded = c_ulong()
    hModule = c_ulong()
    count = c_ulong()
    modname = c_buffer(30)
    PROCESS_QUERY_INFORMATION = 0x0400
    PROCESS_VM_READ = 0x0010
    
    #Call Enumprocesses to get hold of process id's
    psapi.EnumProcesses(byref(lpidProcess),
                        cb,
                        byref(cbNeeded))
    
    #Number of processes returned
    nReturned = cbNeeded.value/sizeof(c_ulong())
    
    pidProcess = [i for i in lpidProcess][:nReturned]
    
    for pid in pidProcess:
        
        #Get handle to the process based on PID
        hProcess = kernel.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                                      False, pid)
        if hProcess:
            psapi.EnumProcessModules(hProcess, byref(hModule), sizeof(hModule), byref(count))
            psapi.GetModuleBaseNameA(hProcess, hModule.value, modname, sizeof(modname))
            print "".join([ i for i in modname if i != '\x00'])
            
            #-- Clean up
            for i in range(modname._length_):
                modname[i]='\x00'
            
            kernel.CloseHandle(hProcess)

if __name__ == '__main__':
    EnumProcesses()

Это довольно умный, но я довольно плохой при разборе CTYPES. Это то, что я хочу учиться, но у меня был крайний срок, доггон! Кроме того, этот только показал список беговых процессов, но нет информации о них. К счастью, автор включал ссылку, но я решил продолжать смотреть.

Затем я нашел нить об использовании HIT Golden Handy WMI модуль Сделать такую вещь (ниже скопировано прямо из темы):

# http://mail.python.org/pipermail/python-win32/2003-December/001482.html
>>> processes = WMI.InstancesOf('Win32_Process')
>>> len(processes)
41
>>> [process.Properties_('Name').Value for process in processes] # get
the process names
[u'System Idle Process', u'System', u'SMSS.EXE', u'CSRSS.EXE',
u'WINLOGON.EXE', u'SERVICES.EXE', u'LSASS.EXE', u'SVCHOST.EXE',
u'SVCHOST.EXE', u'SVCHOST.EXE', u'SVCHOST.EXE', u'SPOOLSV.EXE',
u'ati2evxx.exe', u'BAsfIpM.exe', u'defwatch.exe', u'inetinfo.exe',
u'mdm.exe', u'rtvscan.exe', u'SCARDSVR.EXE', u'WLTRYSVC.EXE',
u'BCMWLTRY.EXE', u'EXPLORER.EXE', u'Apoint.exe', u'carpserv.exe',
u'atiptaxx.exe', u'quickset.exe', u'DSentry.exe', u'Directcd.exe',
u'vptray.exe', u'ApntEx.exe', u'FaxCtrl.exe', u'digstream.exe',
u'CTFMON.EXE', u'wuauclt.exe', u'IEXPLORE.EXE', u'Pythonwin.exe',
u'MMC.EXE', u'OUTLOOK.EXE', u'LineMgr.exe', u'SAPISVR.EXE',
u'WMIPRVSE.EXE']

Here is how to get a single process and get its PID.

>>> p = WMI.ExecQuery('select * from Win32_Process where
Name="Pythonwin.exe"')
>>> [prop.Name for prop in p[0].Properties_] # let's look at all the
process property names
[u'Caption', u'CommandLine', u'CreationClassName', u'CreationDate',
u'CSCreationClassName', u'CSName', u'Description', u'ExecutablePath',
u'ExecutionState', u'Handle', u'HandleCount', u'InstallDate',
u'KernelModeTime', u'MaximumWorkingSetSize', u'MinimumWorkingSetSize',
u'Name', u'OSCreationClassName', u'OSName', u'OtherOperationCount',
u'OtherTransferCount', u'PageFaults', u'PageFileUsage',
u'ParentProcessId', u'PeakPageFileUsage', u'PeakVirtualSize',
u'PeakWorkingSetSize', u'Priority', u'PrivatePageCount', u'ProcessId',
u'QuotaNonPagedPoolUsage', u'QuotaPagedPoolUsage',
u'QuotaPeakNonPagedPoolUsage', u'QuotaPeakPagedPoolUsage',
u'ReadOperationCount', u'ReadTransferCount', u'SessionId', u'Status',
u'TerminationDate', u'ThreadCount', u'UserModeTime', u'VirtualSize',
u'WindowsVersion', u'WorkingSetSize', u'WriteOperationCount',
u'WriteTransferCount']
>>> p[0].Properties_('ProcessId').Value # get our ProcessId
928

Это несколько прохладных вещей, и я использую золотые модули в некоторых из моих других кодов. Тем не менее, я все еще был неопределенным, что и какие счетчики использовать, чтобы добраться до моей информации. Я думал, что большая часть этого материала будет просто закодирована для меня или что-то в этом роде! Ну, оказалось, что там есть пакет, который имеет именно то, что мне нужно, и это работает на всех трех основных платформах! Удивительный!

Кроссплатформенный раствор!

Имя пакета есть Psutil И это было то, что я решил использовать. Вот что я оказался:

import os
import psutil
import time

logPath = r'some\path\proclogs'
if not os.path.exists(logPath):
    os.mkdir(logPath)

separator = "-" * 80
format = "%7s %7s %12s %12s %30s, %s"
format2 = "%7.4f %7.2f %12s %12s %30s, %s"
while 1:
    procs = psutil.get_process_list()
    procs = sorted(procs, key=lambda proc: proc.name)
    
    logPath = r'some\path\proclogs\procLog%i.log' % int(time.time())
    f = open(logPath, 'w')
    f.write(separator + "\n")
    f.write(time.ctime() + "\n")
    f.write(format % ("%CPU", "%MEM", "VMS", "RSS", "NAME", "PATH"))
    f.write("\n")
    
    for proc in procs:
        cpu_percent = proc.get_cpu_percent()
        mem_percent = proc.get_memory_percent()
        rss, vms = proc.get_memory_info()
        rss = str(rss)
        vms = str(vms)
        name = proc.name
        path = proc.path
        f.write(format2 % (cpu_percent, mem_percent, vms, rss, name, path))
        f.write("\n\n")
    f.close()
    print "Finished log update!"
    time.sleep(300)
    print "writing new log data!"

Да, это бесконечная петля и да, это обычно очень плохое, что делать (кроме в программировании GUI). Однако для моей цели мне нужен способ проверить процессы пользователя каждые 5 минут или около того, чтобы увидеть, что вызывает, чтобы машина действовать так странно. Таким образом, скрипт должен работать навсегда и регистрировать результаты в уникальных именованных файлах. Это все этот сценарий, наряду с небольшим форматированием магии. Не стесняйтесь использовать его или нет, как вы видите подходящие.

Я надеюсь, что вы нашли эту коллекцию материала полезными. Надеюсь, это спасет вас всех копающих, я прошел!

ПРИМЕЧАНИЕ. В то время как этот последний скрипт, по-видимому, работает просто в Windows XP, в Windows 7 32 и 64-бит, вы получите «доступом отказано» Traceback, я подозреваю, что это вызвано повышенной безопасностью окна 7, но я постараюсь найти обходной путь.

Обновление (10/09/2010) – Люди Psutil не знают, почему это не работает, но один из их разработчиков подтвердил вопрос. Вы можете следовать на их Список групп Google Отказ