Сообщить об ошибке.

Объект Process модуля psutil в Python

Мониторинг и управление процессами в ОС

Синтаксис:

import psutil

p = psutil.Process(pid=None)

Параметры:

  • pid=None - идентификатор процесса.

Возвращаемое значение:

Описание:

Класс Process() модуля psutil представляет процесс ОС с заданным идентификатором процесса. Если pid опущен, то используется текущий pid процесса (os.getpid()). Если pid не существует, то поднимается исключение psutil.NoSuchProcess. В Linux pid также может ссылаться на идентификатор потока (поле идентификатора, возвращаемое методом Process.threads()).

При доступе к методам класса psutil.Process() всегда нужно быть готовым перехватывать исключения psutil.NoSuchProcess и psutil.AccessDenied.

Чтобы однозначно идентифицировать процесс с течением времени можно использовать встроенную функцию hash() (хэш определяется путем смешивания PID процесса и времени создания). Таким образом, его также можно использовать с типом set.

Примечание. Чтобы эффективно получать более одной информации о процессе одновременно, необходимо использовать диспетчер контекста Process.oneshot() или служебный метод Process.as_dict().

Обратите внимание, что этот класс связывается с процессом уникальным образом через его PID. Это означает, что если процесс завершается, а ОС повторно использует свой PID, то в конечном итоге можно взаимодействовать с другим процессом. Единственные исключения, для которых идентификация процесса предварительно проверяется (через PID + время создания), относятся к следующим методам: Process.nice(), Process.ionice(), Process.cpu_affinity(), Process.rlimit(), Process.children(), Process.parent(), Process.parents(), Process.suspend(), Process.resume(), Process.send_signal(), Process.terminate(), Process.kill().

Чтобы предотвратить эту проблему для всех других методов, можно использовать метод Process.is_running() перед запросом процесса или функцию psutil.process_iter(), если процессы перебираются. Следует отметить, что если не иметь дело с очень "старыми" (неактивными) экземплярами процесса, то вряд ли это будет проблемой.

Process.oneshot():

Менеджер контекста Process.oneshot() значительно ускоряет одновременный поиск и извлечение различной информации об процессе. Различная внутренняя информация о процессе (например, Process.name(), Process.ppid(), Process.uids(), Process.create_time(), …) может быть получена с помощью одной процедуры чтения/извлечения, при этом возвращается только одно значение, а остальные отбрасываются.

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

>>> import psutil
>>> p = psutil.Process()
>>> with p.oneshot():
...     # выполним процедуру получения каких либо сведений.
...     p.name()  
...     # Остальные данные будут извлекаться из кэша
...     p.cpu_times()  # возвращает кэшированное значение
...     p.cpu_percent()  # возвращает кэшированное значение
...     p.create_time()  # возвращает кэшированное значение
...     p.ppid()  # возвращает кэшированное значение
...     p.status()  # возвращает кэшированное значение

Методы объекта Process.


Process.pid:

Свойство Process.pid возвращает собой PID процесса. Это единственный (доступный только для чтения) атрибут класса.

Process.ppid():

Метод Process.ppid() возвращает родительский PID процесса. В Windows возвращаемое значение кэшируется после первого вызова.

В POSIX не кэшируется, т.к. Process.ppid может измениться, если процесс станет зомби.

Дополнительно смотрите методы Process.parent() и Process.parents().

Process.name():

Метод Process.name() возвращает имя процесса. В Windows возвращаемое значение кэшируется после первого вызова.

В POSIX не кэшируется, т.к. имя процесса может измениться.

Process.exe():

Метод Process.exe() возвращает исполняемый процесс как абсолютный путь. В некоторых системах значение может быть пустой строкой. Возвращаемое значение кэшируется после первого вызова.

>>> import psutil
>>> psutil.Process().exe()
# '/usr/bin/python3.10'

Process.cmdline():

Метод Process.cmdline() возвращает командную строку, из которой был вызван этот процесс, представляет собой список строк. Возвращаемое значение не кэшируется, поскольку может измениться командная строка процесса.

>>> import psutil
>>> psutil.Process().cmdline()
# ['python', 'manage.py', 'runserver']

Process.environ():

Метод Process.environ() возвращает переменные окружения процесса в качестве словаря dict.

Примечание. Возвращаемый словарь может не отражать изменения, внесенные после запуска процесса.

>>> import psutil
>>> psutil.Process().environ()
# {
# 'LC_NUMERIC': 'it_IT.UTF-8', 'QT_QPA_PLATFORMTHEME': 'appmenu-qt5', 
# 'IM_CONFIG_PHASE': '1', 'XDG_GREETER_DATA_DIR': '/var/lib/lightdm-data/user', 
# 'GNOME_DESKTOP_SESSION_ID': 'this-is-deprecated', 'XDG_CURRENT_DESKTOP': 'Unity', 
# 'UPSTART_EVENTS': 'started starting', 'GNOME_KEYRING_PID': '', 'XDG_VTNR': '7', 
# 'QT_IM_MODULE': 'ibus', 'LOGNAME': 'user', 'USER': 'user', 'PATH': '/home/...
# ...
# }

Process.create_time():

Метод Process.create_time() возвращает время создания процесса в виде числа float, выраженное в секундах с начала эпохи. Возвращаемое значение кэшируется после первого вызова.

>>> import psutil, datetime
>>> p = psutil.Process()
>>> p.create_time()
# 1307289803.47
>>> t = datetime.datetime.fromtimestamp(p.create_time())
>>> t.strftime("%Y-%m-%d %H:%M:%S")
# '2011-03-05 18:03:52'

Process.as_dict(attrs=None, ad_value=None):

Метод Process.as_dict() представляет собой служебный метод, извлекающий информацию о процессе в виде словаря.

Если атрибут attrs указан, то это должен быть список строк, отражающих доступные имена атрибутов класса psutil.Process(). Вот список возможных строковых значений: 'cmdline', 'connections', 'cpu_affinity', 'cpu_num', 'cpu_percent', 'cpu_times', 'create_time', 'cwd', 'environ', 'exe', 'gids', 'io_counters', 'ionice', 'memory_full_info', 'memory_info', 'memory_maps', 'memory_percent', 'name', 'nice', 'num_ctx_switches', 'num_fds', 'num_handles', 'num_threads', 'open_files', 'pid', 'ppid', 'status', 'terminal', 'threads', 'uids', 'username'. Если аргумент attrs не передан, то предполагаются все общедоступные атрибуты только для чтения.

Аргумент ad_value - это значение, которое присваивается ключу dict в случае возникновения исключения psutil.AccessDenied или psutil.ZombieProcess при получении информации об этом конкретном процессе. Внутри Process.as_dict() использует контекстный менеджер Process.oneshot().

>>> import psutil
>>> p = psutil.Process()
>>> p.as_dict(attrs=['pid', 'name', 'username'])
# {'username': 'user', 'pid': 12366, 'name': 'python'}

# список допустимых имен attrs
>>> list(psutil.Process().as_dict().keys())
# ['status', 'cpu_num', 'num_ctx_switches', 'pid', 'memory_full_info', 
# 'connections', 'cmdline', 'create_time', 'ionice', 'num_fds', 
# 'memory_maps', 'cpu_percent', 'terminal', 'ppid', 'cwd', 'nice', 
# 'username', 'cpu_times', 'io_counters', 'memory_info', 'threads', 
# 'open_files', 'name', 'num_threads', 'exe', 'uids', 'gids', 'cpu_affinity', 
# 'memory_percent', 'environ']

Process.parent():

Метод Process.parent() возвращает родительский процесс как объект Process, предварительно проверяя, был ли повторно использован PID. Если родительский PID не известен, то возвращает None.

Дополнительно смотрите методы Process.ppid() и Process.parents().

Process.parents():

Метод Process.parents() возвращает родителей этого процесса в виде списка экземпляров Process. Если ни один из родителей не известен, то возвращает пустой список [].

Дополнительно смотрите методы Process.ppid() и Process.parent().

Process.status():

Метод Process.status() возвращает текущее состояние процесса в виде строки. Возвращаемая строка является одной из констант psutil.STATUS_*

Process.cwd():

Метод Process.cwd() возвращает текущий рабочий каталог процесса в качестве абсолютного пути.

Process.username():

Метод Process.username() возвращает имя пользователя, которому принадлежит процесс. В UNIX это рассчитывается с использованием реального идентификатора процесса.

Process.uids():

Метод Process.uids() возвращает реальный, эффективный и сохраненный идентификатор пользователя этого процесса в виде именованного кортежа.

Это то же самое, что и os.getresuid, но может использоваться для любого PID процесса.

Доступность: UNIX

Process.gids():

Метод Process.gids() возвращает реальный, эффективный и сохраненный идентификатор группы этого процесса в виде именованного кортежа.

Это то же самое, что и os.getresgid, но может использоваться для любого PID процесса.

Доступность: UNIX

Process.terminal():

Метод Process.terminal() возвращает терминал, связанный с этим процессом, если он есть, иначе None.

Это похоже на команду tty, но может использоваться для любого PID процесса.

Доступность: UNIX

Process.nice(value=None):

Метод Process.nice() получает или устанавливает приоритет процесса. В UNIX это число, которое обычно находится в диапазоне от -20 до 20. Чем выше значение nice, тем ниже приоритет процесса.

>>> import psutil
>>> p = psutil.Process()
# устанавливаем приоритет процесса
>>> p.nice(10)  
# получаем приоритет процесса
>>> p.nice()
# 10

Эта функциональность также доступна как os.getpriority и os.setpriority.

В Windows это реализуется через API-интерфейсы Windows GetPriorityClass и SetPriorityClass, а значение является одной из констант psutil.*_PRIORITY_CLASS, отражающих документацию MSDN.

Пример, который увеличивает приоритет процесса в Windows:

>>> p.nice(psutil.HIGH_PRIORITY_CLASS)

Process.ionice(ioclass=None, value=None):

Метод Process.ionice() получает или устанавливает приоритет ввода-вывода процесса. Если аргументы не указаны, то функция извлекает/получает приоритет, возвращая кортеж (ioclass, value) в Linux и целое число ioclass в Windows. Если предоставляется аргумент ioclass, то функция пытается установить приоритет. В этом случае дополнительное значение value можно указать только в Linux (чтобы еще больше повысить или понизить приоритет ввода-вывода).

Возможные значения ioclass, зависящие от платформы.

  • Linux (см. руководство ioprio_get):
    • IOPRIO_CLASS_RT: (высокий) процесс каждый раз получает первый доступ к диску. Используйте его с осторожностью, так как это может привести к истощению всей системы. Можно указать дополнительный уровень приоритета, который варьируется от 0 (самый высокий) до 7 (самый низкий).
    • IOPRIO_CLASS_BE: (нормальный) значение по умолчанию для любого процесса, который не установил определенный приоритет ввода-вывода. Дополнительный уровень приоритета варьируется от 0 (самый высокий) до 7 (самый низкий).
    • IOPRIO_CLASS_IDLE: (низкий) получает время ввода-вывода, когда диск больше никому не нужен. Никакие дополнительные значения не принимаются.
    • IOPRIO_CLASS_NONE: возвращает, если ранее не был установлен приоритет.
  • Windows:
    • IOPRIO_HIGH: наивысший приоритет.
    • IOPRIO_NORMAL: приоритет по умолчанию.
    • IOPRIO_LOW: низкий приоритет.
    • IOPRIO_VERYLOW: самый низкий приоритет.

Пример того, как установить наивысший приоритет ввода-вывода в зависимости от платформы:

>>> import psutil
>>> p = psutil.Process()
>>> if psutil.LINUX:
...     p.ionice(psutil.IOPRIO_CLASS_RT, value=7)
... else:
...     p.ionice(psutil.IOPRIO_HIGH)

# смотрим приоритет
>>> p.ionice()
pionice(ioclass=<IOPriority.IOPRIO_CLASS_RT: 1>, value=7)

Доступность: Linux, Windows Vista+

Process.rlimit(resource, limits=None):

Метод Process.rlimit() получает или устанавливает лимиты ресурсов процесса (см. man prlimit).

Аргумент resource является одной из констант psutil.RLIMIT_*.

Аргумент limit - это кортеж (soft, hard). Это то же самое, что и resource.getrlimit() и resource.setrlimit(), но может использоваться для любого PID процесса, а не только для os.getpid(). При получении, возвращаемое значение представляет собой кортеж (soft, hard). Каждое значение может быть либо целым, либо константой psutil.RLIMIT_*.

Пример:

>>> import psutil
>>> p = psutil.Process()
# установим ограничение процессу, чтобы он мог 
# открыть открыть максимум 128 файловых дескрипторов
>>> p.rlimit(psutil.RLIMIT_NOFILE, (128, 128))
# и мог создавать файлы размером не более 1024 байт
>>> p.rlimit(psutil.RLIMIT_FSIZE, (1024, 1024))
# смотрим что получилось
>>> p.rlimit(psutil.RLIMIT_FSIZE)
# (1024, 1024)

Доступность: Linux, FreeBSD

Process.io_counters():

Метод Process.io_counters() возвращает статистику ввода-вывода процесса в виде именованного кортежа.

Для Linux можно обратиться к документации по файловой системе /proc.

  • read_count: количество совокупно выполненных операций чтения. Предполагается, что это подсчитывает количество системных вызовов, связанных с чтением, таких как read() и pread() в UNIX.
  • write_count: количество совокупно выполненных операций записи. Предполагается, что это подсчитывает количество системных вызовов, связанных с записью, таких как write() и pwrite() в UNIX.
  • read_bytes: количество кумулятивно прочитанных байтов. На BSD всегда -1.
  • write_bytes: количество кумулятивно записанных байт. На BSD всегда -1.

Специфичные для Linux:

  • read_chars (Linux): количество байтов, которые этот процесс совокупно передал системным вызовам read() и pread(). В отличие от read_bytes, не имеет значения, происходил ли фактический ввод-вывод на физическом диске.
  • write_chars (Linux): количество байтов, которые этот процесс совокупно передал системным вызовам write() и pwrite(). В отличие от write_bytes, не имеет значения, происходил ли фактический ввод-вывод на физический диск.

Специфичные для Windows:

  • other_count (Windows): количество выполненных операций ввода-вывода, отличных от операций чтения и записи.
  • other_bytes (Windows): количество байтов, передаваемых во время операций, отличных от операций чтения и записи.
>>> import psutil
>>> p = psutil.Process()
>>> p.io_counters()
# pio(read_count=454556, write_count=3456, read_bytes=110592, 
#     write_bytes=0, read_chars=769931, write_chars=203)

Доступность: Linux, BSD, Windows, AIX

Process.num_ctx_switches():

Метод Process.num_ctx_switches() возвращает количество добровольных и непроизвольных переключений контекста, совокупно выполненных этим процессом.

Process.num_fds():

Метод Process.num_fds() возвращает количество файловых дескрипторов, открытых в данный момент этим процессом (не совокупно).

Доступность: UNIX

Process.num_handles():

Метод Process.num_handles() возвращает количество дескрипторов, используемых в данный момент этим процессом (не совокупно).

Доступность: Windows

Process.num_threads():

Метод Process.num_threads() возвращает количество потоков, используемых в данный момент этим процессом (не совокупно).

Process.threads():

Метод Process.threads() возвращает потоки, открытые процессом, в виде списка именованных кортежей. В OpenBSD этот метод требует привилегий root.

  • id: собственный идентификатор потока, назначенный ядром. Если pid относится к текущему процессу, то он соответствует атрибуту native_id класса threading.Thread и может использоваться для ссылки на отдельные потоки Python, работающие в собственном приложении Python.
  • user_time: время, проведенное в пользовательском режиме.
  • system_time: время, проведенное в режиме ядра.

Process.cpu_times():

Метод Process.cpu_times() возвращает именованный кортеж, представляющий суммарное время обработки в секундах (объяснение). Метод похож на os.times, но может использоваться для любого PID процесса.

  • user: время, проведенное в пользовательском режиме.
  • system: время, проведенное в режиме ядра.
  • children_user: пользовательское время всех дочерних процессов (всегда 0 в Windows и macOS).
  • children_system: системное время всех дочерних процессов (всегда 0 в Windows и macOS).
  • iowait: (Linux) время, потраченное на ожидание завершения блокировки ввода-вывода. Это значение исключается из подсчета пользовательского и системного времени (т.к. ЦП не выполняет никакой работы).
>>> import psutil
>>> p = psutil.Process()
>>> p.cpu_times()
# pcputimes(user=0.03, system=0.67, children_user=0.0, 
#           children_system=0.0, iowait=0.08)

# совокупно, исключая детей и `iowait`
>>> sum(p.cpu_times()[:2]) 
# 0.70

Process.cpu_percent(interval=None):

Метод Process.cpu_percent() возвращает число float, представляющее использование ЦП процессом в процентах, которое также может быть равно 100,0 в случае, если процесс выполняет несколько потоков на разных ЦП.

Когда аргумент interval > 0,0, то время обработки сравнивается с временем процессора системы, прошедшим до и после интервала (блокирующий вызов). Когда interval равен 0,0 или None, время обработки сравнивается с временем процессора системы, прошедшим с момента последнего вызова, и немедленно возвращается. Это означает, что при первом вызове он вернет бессмысленное значение 0.0, которое необходимо игнорировать. В этом случае для точности рекомендуется вызывать эту функцию второй раз с интервалом не менее 0,1 секунды между вызовами.

Пример:

>>> import psutil
>>> p = psutil.Process()
# блокирующий вызов
>>> p.cpu_percent(interval=1)
# 2.0

# неблокирующий вызов 
# (процент с момента последнего звонка)
>>> p.cpu_percent(interval=None)
# 2.9

Примечания:

  • возвращаемое значение может быть > 100,0 в случае, если процесс выполняет несколько потоков на разных ядрах ЦП.
  • возвращаемое значение явно не распределяется поровну между всеми доступными процессорами (в отличие от psutil.cpu_percent()). Это означает, что процесс цикла занятости, запущенный в системе с двумя логическими ЦП, будет сообщен как имеющий 100% загрузку ЦП вместо 50%. Это было сделано для того, чтобы соответствовать утилите UNIX top, а также чтобы было проще идентифицировать процессы, потребляющие ресурсы ЦП, независимо от количества ЦП. Следует отметить, что taskmgr.exe в Windows ведет себя не так (он сообщает об использовании 50%). Чтобы эмулировать поведение taskmgr.exe, можно сделать: p.cpu_percent() / psutil.cpu_count().

Предупреждение: при ПЕРВОМ ВЫЗОВЕ этого метода с interval=0,0 или interval=None, он вернет бессмысленное значение 0,0, которое необходимо игнорировать.

Process.cpu_affinity(cpus=None):

Метод Process.cpu_affinity() получает или устанавливает привязку процессора к текущему процессу. Привязка ЦП состоит в указании ОС запускать процесс только на ограниченном наборе ЦП (в Linux используется команда taskset).

Если аргумент cpus не передан, то метод возвращает текущую привязку ЦП в виде списка целых чисел. Если передан, то это должен быть список целых чисел, определяющих привязку для конкретных процессоров. Если передается пустой список, то предполагаются (и устанавливаются) все подходящие процессоры.

В некоторых системах, таких как Linux, это может означать все доступные логические ЦП, как в list(range(psutil.cpu_count())).

>>> import psutil
>>> psutil.cpu_count()
# 4
>>> p = psutil.Process()
# получаем привязку
>>> p.cpu_affinity()
# [0, 1, 2, 3]

# устанавливаем привязку 
# с этого момента процесс будет выполняться
# только на процессорах #0 и #1
>>> p.cpu_affinity([0, 1])
>>> p.cpu_affinity()
# [0, 1]

# сбрасываем привязку ко всем
# подходящим процессорам
>>> p.cpu_affinity([])

Доступность: Linux, Windows, FreeBSD

Process.cpu_num():

Метод Process.cpu_num() возвращает, на каком ЦП в данный момент работает этот процесс (или какие ЦП использует). Возвращаемое число должно быть <= psutil.cpu_count(). Во FreeBSD определенный процесс ядра может возвращать -1.

Метод можно использовать в сочетании с psutil.cpu_percent(percpu=True) для наблюдения за рабочей нагрузкой системы, распределенной между несколькими процессорами.

Доступность: Linux, FreeBSD, SunOS

Смотрите пример "Пример вывода рабочей нагрузки, распределенной по разным ЦП".

Process.memory_info():

Метод Process.memory_info() возвращает именованный кортеж с полями (разными в зависимости от платформы), представляющей информацию о памяти, которую занимает/использует процесс. "Переносимые" (portable) поля, доступны на всех платформах (это rss и vms). Все числа выражены в байтах.

  • rss: физическая память без подкачки, которую использовал процесс. В UNIX соответствует столбцу RES утилиты top. В Windows это псевдоним для поля wset, и он соответствует столбцу Mem Usage в taskmgr.exe.
  • vms: общий объем виртуальной памяти, используемой процессом. В UNIX он соответствует столбцу VIRT утилиты top. В Windows это псевдоним для поля файла подкачки, и он соответствует столбцу VM Size в taskmgr.exe.
  • shared: (Linux) память, которая может быть потенциально разделена с другими процессами. Соответствует столбцу SHR утилиты top.
  • text (Linux, BSD): также известен как TRS - объем памяти, выделенный для исполняемого кода. Соответствует столбцу CODE утилиты top.
  • data (Linux, BSD): также известен как DRS объем физической памяти, выделенный для кода, отличного от исполняемого. Соответствует столбцу DATA утилиты top.
  • lib (Linux): память, используемая разделяемыми библиотеками.
  • dirty (Linux): количество грязных страниц.
  • pfaults (macOS): количество ошибок страницы.
  • pageins (macOS): количество фактических страниц.

Пример для Linux:

>>> import psutil
>>> p = psutil.Process()
>>> p.memory_info()
# pmem(rss=15491072, vms=84025344, shared=5206016, 
#      text=2555904, lib=0, data=9891840, dirty=0)

Process.memory_full_info():

Метод Process.memory_full_info() возвращает ту же информацию, что и Process.memory_info(), плюс на некоторых платформах (Linux, macOS, Windows) также предоставляет дополнительные показатели (USS, PSS и swap). Дополнительные метрики обеспечивают лучшее представление об "эффективном" потреблении памяти процессом (в случае USS). Метод передает весь адрес процесса, таким образом, он обычно требует более высоких пользовательских привилегий, чем Process.memory_info(), и работает значительно медленнее. На платформах, где дополнительные поля не реализованы, метод просто возвращает те же метрики, что и Process.memory_info().

Описание дополнительных метрик:

  • uss (Linux, macOS, Windows): это память, которая уникальна для процесса и которая будет освобождена, если процесс будет завершен прямо сейчас.
  • pss (Linux): это объем памяти, совместно используемой с другими процессами, учитываемый таким образом, что объем делится поровну между процессами, которые его совместно используют. т.е. если процесс имеет 10 МБ для себя и 10 МБ для совместного использования с другим процессом, его PSS будет 15 МБ.
  • swap (Linux): объем памяти, который был выгружен на диск.

Обратите внимание, что uss, вероятно, является наиболее репрезентативной метрикой для определения того, сколько памяти фактически используется процессом. Он представляет собой объем памяти, который был бы освобожден, если бы процесс был завершен прямо сейчас.

Пример для Linux:

>>> import psutil
>>> p = psutil.Process()
>>> p.memory_full_info()
# pfullmem(rss=10199040, vms=52133888, shared=3887104, 
#          text=2867200, lib=0, data=5967872, dirty=0, 
#          uss=6545408, pss=6872064, swap=0)

Смотрите пример "Подробное использование памяти всеми процессами".

Process.memory_percent(memtype="rss"):

Метод Process.memory_percent() сравнивает память процесса с общей физической памятью системы и рассчитывает использование памяти процесса в процентах.

Аргумент memtype - это строка, определяющая, с каким типом памяти процесса необходимо сравнить. Можно выбирать между именованными именами полей кортежа, возвращаемыми функциями Process.memory_info() и Process.memory_full_info() (по умолчанию 'rss').

Process.memory_maps(grouped=True):

Метод Process.memory_maps() возвращает сопоставленные области памяти процесса в виде списка именованных кортежей, поля которых являются разными в зависимости от платформы. Этот метод полезен для получения подробного представления об использовании памяти процесса (наиболее важным значением является private_* память).

Если аргумент grouped имеет значение True, то сопоставленные области с одинаковым путем группируются вместе, а разные поля памяти суммируются. Если для параметра grouped установлено значение False, то каждый сопоставленный регион отображается как единый объект, а именованный кортеж также будет включать адресное пространство сопоставленного региона (addr) и набор разрешений (perms).

Смотрите пример "Пример вывода карты памяти процесса".

>>> import psutil
>>> p = psutil.Process()
>>> p.memory_maps()
# [
# pmmap_grouped(path='/lib/x8664-linux-gnu/libutil-2.15.so', rss=32768, 
#               size=2125824, pss=32768, shared_clean=0, 
#               shared_dirty=0, private_clean=20480, private_dirty=12288, 
#               referenced=32768, anonymous=12288, swap=0),
# pmmap_grouped(path='/lib/x8664-linux-gnu/libc-2.15.so', rss=3821568, 
#               size=3842048, pss=3821568, shared_clean=0, 
#               shared_dirty=0, private_clean=0, private_dirty=3821568, 
#               referenced=3575808, anonymous=3821568, swap=0),
#  ...]

Доступность: Linux, Windows, FreeBSD, SunOS

Process.children(recursive=False):

Метод Process.children() возвращает дочерние элементы этого процесса в виде списка экземпляров Process. Если аргумент recursive равен True, то возвращает всех родительских потомков. Пример псевдокода, предполагающий, что A == этот процесс:

A ─┐
   │
   ├─ B (child) ─┐
   │             └─ X (grandchild) ─┐
   │                                └─ Y (great grandchild)
   ├─ C (child)
└─ D (child)
>>> p.children()
# B, C, D
>>> p.children(recursive=True)
# B, X, Y, C, D

Обратите внимание, что в приведенном выше примере, если процесс X исчезнет, ​​то процесс Y также не будет возвращен, так как ссылка на процесс A будет потеряна.

Дополнительно смотрите "Пример уничтожение дерева процессов".

Process.open_files():

Метод Process.open_files() возвращает пути к обычным файлам, которые процесс открыл, в виде списка именованных кортежей, включая следующие поля:

  • path: абсолютное имя файла;
  • fd: номер дескриптора файла, в Windows, всегда -1.

Только для Linux:

  • position (Linux): положение указателя в файле (смещение).
  • mode (Linux): строка, указывающая, как файл был открыт, аналогично аргументу mode функции open(). Нет разницы между файлами, открытыми в двоичном или текстовом режиме.
  • flags (Linux): флаги, которые были переданы базовой операции открытия файла os.open() (например, os.O_RDONLY, os.O_TRUNC и т.д.).
>>> import psutil
>>> f = open('file.ext', 'w')
>>> p = psutil.Process()
>>> p.open_files()
# [
#   popenfile(path='/home/user/svn/psutil/file.ext', fd=3, 
#             position=0, mode='w', flags=32769)
# ]

Предупреждение для Windows: этот метод ненадежен из-за некоторых ограничений базового API Windows, может зависать при получении дескрипторов определенных файлов. Чтобы обойти такое поведение, модуль psutil порождает поток для определения имени дескриптора файла и убивает его, если он не отвечает через 100 мс. Это означает, что этот метод в Windows не гарантирует перечисление всех обычных файловых дескрипторов. Такое же ограничение имеют инструменты, такие как ProcessHacker.

Предупреждение для BSD: этот метод может возвращать файлы с пустым путем из-за ошибки ядра, поэтому он ненадежен.

Process.connections(kind="inet"):

Метод Process.connections() возвращает соединения сокетов, открытые процессом, в виде списка именованных кортежей. Чтобы получить общесистемные соединения, используйте psutil.net_connections().

Каждый именованный кортеж предоставляет 6 атрибутов:

  • fd: дескриптор файла сокета. Если соединение относится к текущему процессу, это может быть передано socket.fromfd() для получения пригодного для использования объекта сокета. В Windows и SunOS это значение всегда равно -1.
  • family: семейство адресов, либо AF_INET, AF_INET6, либо AF_UNIX.
  • type: тип адреса: SOCK_STREAM, SOCK_DGRAM или SOCK_SEQPACKET.
  • laddr: локальный адрес в виде (ip, port), именованный кортеж или путь path в случае сокетов AF_UNIX. Для сокетов UNIX смотрите примечания ниже.
  • raddr: удаленный адрес в виде (ip, port), именованный кортеж или абсолютный путь path в случае сокетов UNIX. Когда удаленная конечная точка не подключена, то возвращается пустой кортеж (AF_INET*) или '' (AF_UNIX). Для сокетов UNIX смотрите примечания ниже.
  • status: представляет состояние TCP-соединения. Возвращаемое значение является одной из констант psutil.CONN_* (строка). Для сокетов UDP и UNIX это всегда будет psutil.CONN_NONE.

Аргумент kind представляет собой строку, которая фильтрует соединения, соответствующие следующим критериям.

Аргумент kindСоединения с использованием
"inet"IPv4 и IPv6
"inet4"IPv4
"inet6"IPv6
"tcp"TCP
"tcp4"TCP поверх IPv4
"tcp6"TCP поверх IPv6
"udp"UDP
"udp4"UDP поверх IPv4
"udp6"UDP поверх IPv6
"unix"Сокет UNIX (как протоколы UDP, так и TCP)
"all"сумма всех возможных семейств и протоколов

Пример:

>>> import psutil
>>> p = psutil.Process(1694)
>>> p.name()
# 'firefox'
>>> p.connections()
# [
#   pconn(fd=115, family=<AddressFamily.AF_INET: 2>, 
#         type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), 
#         raddr=addr(ip='93.186.135.91', port=80), status='ESTABLISHED'),
# pconn(fd=117, family=<AddressFamily.AF_INET: 2>, 
#         type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=43761), 
#         raddr=addr(ip='72.14.234.100', port=80), status='CLOSING'),
# pconn(...)
# ...
# ]

Примечания:

  • (Solaris) сокеты UNIX не поддерживаются.
  • (Linux, FreeBSD) поле raddr для сокетов UNIX всегда имеет значение ''. Это ограничение ОС.
  • (в OpenBSD) поля laddr и raddr для сокетов UNIX всегда имеют значение ''. Это ограничение ОС.
  • (AIX) всегда вызывается исключение psutil.AccessDenied, если только метод не запущен от имени пользователя root (lsof делает то же самое).

Process.is_running():

Метод Process.is_running() проверяет, выполняется ли текущий процесс в текущем списке процессов. Метод надежен также в случае, если процесс упал, а его PID повторно используется другим процессом.

Этот метод следует предпочесть выполнению функции psutil.pid_exists(p.pid).

Обратите внимание, что он также вернет True, если процесс является зомби (p.status() == psutil.STATUS_ZOMBIE).

Process.send_signal(signal):

Метод Process.send_signal() отправляет сигнал процессу (смотрите константы модуля signal), упреждающе проверяя, был ли повторно использован PID.

  • В UNIX это то же самое, что и os.kill(pid, sig).
  • В Windows поддерживаются только сигналы SIGTERM, CTRL_C_EVENT и CTRL_BREAK_EVENT, а SIGTERM рассматривается как псевдоним для kill().

Дополнительно смотрите "Пример уничтожение дерева процессов".

Process.suspend():

Метод Process.suspend() приостанавливает выполнение процесса с помощью сигнала SIGSTOP, упреждающе проверяя, был ли повторно использован PID.

  • В UNIX это то же самое, что и os.kill(pid, signal.SIGSTOP).
  • В Windows это делается путем приостановки выполнения всех потоков процесса.

Process.resume():

Метод Process.resume() возобновляет выполнения процесса с сигналом SIGCONT, упреждающе проверяющим, был ли повторно использован PID.

  • В UNIX это то же самое, что и os.kill(pid, signal.SIGCONT).
  • В Windows это делается путем возобновления выполнения всех потоков процесса.

Process.terminate():

Метод Process.terminate() завершает процесс сигналом SIGTERM, предварительно проверив, был ли повторно использован PID.

  • В UNIX это то же самое, что и [os.kill(pid, signal.SIGTERM)][].
  • В Windows это псевдоним kill().

Process.kill():

Метод Process.kill() уничтожает текущий процесс с помощью сигнала SIGKILL, упреждающе проверяя, был ли повторно использован PID.

  • В UNIX это то же самое, что и os.kill(pid, signal.SIGKILL).
  • В Windows это делается с помощью TerminateProcess.

Process.wait(timeout=None):

Метод Process.wait() дожидается завершения PID процесса. Возвращаемые значения различаются в UNIX и Windows.

В UNIX: если процесс завершился нормально, то возвращаемое значение представляет собой положительное целое число >= 0, указывающее код выхода. Если процесс был прерван по сигналу, то возвращает отрицательное значение сигнала, вызвавшего завершение (например, -SIGTERM). Если PID не является потомком os.getpid (текущего процесса), то просто будет ждать, пока процесс не исчезнет, ​​и вернет None. Если PID не существует, то немедленно возвращает None.

В Windows: всегда возвращает код выхода, который является положительным целым числом, возвращаемым Windows API GetExitCodeProcess.

Аргумент timeout выражается в секундах. Если указан и процесс все еще жив, то вызывает исключение TimeoutExpired. При timeout=0 можно использовать в неблокирующих приложениях: метод либо возвращает значение немедленно, либо поднимет значение TimeoutExpired.

Возвращаемое значение кэшируется. Для ожидания нескольких процессов нужно использовать функцию psutil.wait_procs().

>>> import psutil
>>> p = psutil.Process(9891)
>>> p.terminate()
>>> p.wait()
# <Negsignal.SIGTERM: -15>

Дополнительно смотрите "Пример уничтожение дерева процессов".


Пример уничтожение дерева процессов.

import os
import signal
import psutil

def kill_proc_tree(pid, sig=signal.SIGTERM, include_parent=True,
                   timeout=None, on_terminate=None):
    """Уничтожает дерево процессов (включая внуков) 
    сигналом 'sig' и возвращает кортеж `(gone, still_alive)`. 
    Аргумент 'on_terminate', если указан, является 
    функцией обратного вызова, которая вызывается, 
    как только завершается дочерний процесс.
    """
    assert pid != os.getpid(), "не может убить сама себя"
    parent = psutil.Process(pid)
    children = parent.children(recursive=True)
    if include_parent:
        children.append(parent)
    for p in children:
        try:
            p.send_signal(sig)
        except psutil.NoSuchProcess:
            pass
    gone, alive = psutil.wait_procs(children, timeout=timeout,
                                    callback=on_terminate)
    return (gone, alive)

Пример вывода рабочей нагрузки, распределенной по разным ЦП.

import collections
import os
import sys
import time

import psutil
from psutil._compat import get_terminal_size

if not hasattr(psutil.Process, "cpu_num"):
    sys.exit("platform not supported")

def clean_screen():
    if psutil.POSIX:
        os.system('clear')
    else:
        os.system('cls')

def main():
    num_cpus = psutil.cpu_count()
    if num_cpus > 8:
        num_cpus = 8  # try to fit into screen
        cpus_hidden = True
    else:
        cpus_hidden = False

    while True:
        # вывод заголовка
        clean_screen()
        cpus_percent = psutil.cpu_percent(percpu=True)
        for i in range(num_cpus):
            print("CPU %-6i" % i, end="")
        if cpus_hidden:
            print(" (+ hidden)", end="")

        print()
        for _ in range(num_cpus):
            print("%-10s" % cpus_percent.pop(0), end="")
        print()

        # процессы
        procs = collections.defaultdict(list)
        for p in psutil.process_iter(['name', 'cpu_num']):
            procs[p.info['cpu_num']].append(p.info['name'][:5])

        curr_line = 3
        while True:
            for num in range(num_cpus):
                try:
                    pname = procs[num].pop()
                except IndexError:
                    pname = ""
                print("%-10s" % pname[:10], end="")
            print()
            curr_line += 1
            if curr_line >= get_terminal_size()[1]:
                break

        time.sleep(1)

if __name__ == '__main__':
    main()

Вывод сценария:

$ python3 test.py
CPU 0     CPU 1     CPU 2     CPU 3     CPU 4     CPU 5     CPU 6     CPU 7
19.8      20.6      18.2      15.8      6.9       17.3      5.0       20.4
gvfsd     pytho     kwork     chrom     unity     kwork     kwork     kwork
chrom     chrom     indic     ibus-     whoop     nfsd      (sd-p     gvfsd
ibus-     cat       at-sp     chrom     Modem     nfsd4     light     upsta
ibus-     iprt-     ibus-     nacl_     cfg80     kwork     nfsd      bluet
chrom     irqba     gpg-a     chrom     ext4-     biose     nfsd      dio/n
chrom     acpid     bamfd     nvidi     kwork     scsi_     sshd      rpc.m
upsta     rsysl     dbus-     nfsd      biose     scsi_     ext4-     polki
rtkit     avahi     upowe     Netwo     scsi_     biose     UVM T     irq/9
[...]

Просмотр подробного использования памяти всеми процессами.

Пример представляет собой подробный вывод использования памяти всеми (поддерживаемыми запросом) процессами. Процессы сортируются по памяти USS, т.е. наиболее репрезентативный показатель для определения объема памяти фактически используемой процессом.

Пример похож на утилиту командной строки smem в Linux:

import sys
import psutil

if not (psutil.LINUX or psutil.MACOS or psutil.WINDOWS):
    sys.exit("платформа не поддерживается")

def convert_bytes(n):
    symbols = ('K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y')
    prefix = {}
    for i, s in enumerate(symbols):
        prefix[s] = 1 << (i + 1) * 10
    for s in reversed(symbols):
        if n >= prefix[s]:
            value = float(n) / prefix[s]
            return '%.1f%s' % (value, s)
    return "%sB" % n

def main():
    ad_pids = []
    procs = []
    for p in psutil.process_iter():
        with p.oneshot():
            try:
                mem = p.memory_full_info()
                info = p.as_dict(["cmdline", "username"])
            except psutil.AccessDenied:
                ad_pids.append(p.pid)
            except psutil.NoSuchProcess:
                pass
            else:
                p._uss = mem.uss
                p._rss = mem.rss
                if not p._uss:
                    continue
                p._pss = getattr(mem, "pss", "")
                p._swap = getattr(mem, "swap", "")
                p._info = info
                procs.append(p)

    procs.sort(key=lambda p: p._uss)
    templ = "%-7s %-7s %7s %7s %7s %7s %7s"
    print(templ % ("PID", "User", "USS", "PSS", "Swap", "RSS", "Cmdline"))
    print("=" * 78)
    for p in procs[:86]:
        cmd = " ".join(p._info["cmdline"])[:50] if p._info["cmdline"] else ""
        line = templ % (
            p.pid,
            p._info["username"][:7] if p._info["username"] else "",
            convert_bytes(p._uss),
            convert_bytes(p._pss) if p._pss != "" else "",
            convert_bytes(p._swap) if p._swap != "" else "",
            convert_bytes(p._rss),
            cmd,
        )
        print(line)
    if ad_pids:
        print("warning: access denied for %s pids" % (len(ad_pids)),
              file=sys.stderr)


if __name__ == '__main__':
    sys.exit(main())

Вывод сценария:

$ python3 test.py
PID     User    Cmdline                            USS     PSS    Swap     RSS
==============================================================================
[...]
3986    user /usr/bin/python3 /usr/bin/indi   15.3M   16.6M      0B   25.6M
3906    user /usr/lib/ibus/ibus-ui-gtk3       17.6M   18.1M      0B   26.7M
3991    user python /usr/bin/hp-systray -x    19.0M   23.3M      0B   40.7M
3830    user /usr/bin/ibus-daemon --daemoni   19.0M   19.0M      0B   21.4M
20529   user /opt/sublime_text/plugin_host    19.9M   20.1M      0B   22.0M
3990    user nautilus -n                      20.6M   29.9M      0B   50.2M
3898    user /usr/lib/unity/unity-panel-ser   27.1M   27.9M      0B   37.7M
[...]

Пример вывода карты памяти процесса.

Пример представляет собой клон утилиты pmap в Linux.

import sys
import psutil
from psutil._common import bytes2human
from psutil._compat import get_terminal_size

def safe_print(s):
    s = s[:get_terminal_size()[0]]
    try:
        print(s)
    except UnicodeEncodeError:
        print(s.encode('ascii', 'ignore').decode())

def main():
    if len(sys.argv) != 2:
        sys.exit('usage: pmap <pid>')
    p = psutil.Process(int(sys.argv[1]))
    templ = "%-20s %10s  %-7s %s"
    print(templ % ("Address", "RSS", "Mode", "Mapping"))
    total_rss = 0
    for m in p.memory_maps(grouped=False):
        total_rss += m.rss
        safe_print(templ % (
            m.addr.split('-')[0].zfill(16),
            bytes2human(m.rss),
            m.perms,
            m.path))
    print("-" * 31)
    print(templ % ("Total", bytes2human(total_rss), '', ''))
    safe_print("PID = %s, name = %s" % (p.pid, p.name()))


if __name__ == '__main__':
    main()

Вывод сценария:

$ python3 test.py 32402
Address                 RSS  Mode    Mapping
0000000000400000      1200K  r-xp    /usr/bin/python3.10
0000000000838000         4K  r--p    /usr/bin/python3.10
0000000000839000       304K  rw-p    /usr/bin/python3.10
00000000008ae000        68K  rw-p    [anon]
000000000275e000      5396K  rw-p    [heap]
00002b29bb1e0000       124K  r-xp    /lib/x86_64-linux-gnu/ld-2.17.so
00002b29bb203000         8K  rw-p    [anon]
[...]

Пример вывода подробной информации о процессе.

import argparse
import datetime
import socket
import sys
import psutil
from psutil._common import bytes2human

ACCESS_DENIED = ''
NON_VERBOSE_ITERATIONS = 4
RLIMITS_MAP = {
    "RLIMIT_AS": "virtualmem",
    "RLIMIT_CORE": "coredumpsize",
    "RLIMIT_CPU": "cputime",
    "RLIMIT_DATA": "datasize",
    "RLIMIT_FSIZE": "filesize",
    "RLIMIT_MEMLOCK": "memlock",
    "RLIMIT_MSGQUEUE": "msgqueue",
    "RLIMIT_NICE": "nice",
    "RLIMIT_NOFILE": "openfiles",
    "RLIMIT_NPROC": "maxprocesses",
    "RLIMIT_NPTS": "pseudoterms",
    "RLIMIT_RSS": "rss",
    "RLIMIT_RTPRIO": "realtimeprio",
    "RLIMIT_RTTIME": "rtimesched",
    "RLIMIT_SBSIZE": "sockbufsize",
    "RLIMIT_SIGPENDING": "sigspending",
    "RLIMIT_STACK": "stack",
    "RLIMIT_SWAP": "swapuse",
}

def print_(a, b):
    if sys.stdout.isatty() and psutil.POSIX:
        fmt = '\x1b[1;32m%-13s\x1b[0m %s' % (a, b)
    else:
        fmt = '%-11s %s' % (a, b)
    print(fmt)

def str_ntuple(nt, convert_bytes=False):
    if nt == ACCESS_DENIED:
        return ""
    if not convert_bytes:
        return ", ".join(["%s=%s" % (x, getattr(nt, x)) for x in nt._fields])
    else:
        return ", ".join(["%s=%s" % (x, bytes2human(getattr(nt, x)))
                          for x in nt._fields])

def run(pid, verbose=False):
    try:
        proc = psutil.Process(pid)
        pinfo = proc.as_dict(ad_value=ACCESS_DENIED)
    except psutil.NoSuchProcess as err:
        sys.exit(str(err))

    # collect other proc info
    with proc.oneshot():
        try:
            parent = proc.parent()
            if parent:
                parent = '(%s)' % parent.name()
            else:
                parent = ''
        except psutil.Error:
            parent = ''
        try:
            pinfo['children'] = proc.children()
        except psutil.Error:
            pinfo['children'] = []
        if pinfo['create_time']:
            started = datetime.datetime.fromtimestamp(
                pinfo['create_time']).strftime('%Y-%m-%d %H:%M')
        else:
            started = ACCESS_DENIED

    print_('pid', pinfo['pid'])
    print_('name', pinfo['name'])
    print_('parent', '%s %s' % (pinfo['ppid'], parent))
    print_('exe', pinfo['exe'])
    print_('cwd', pinfo['cwd'])
    print_('cmdline', ' '.join(pinfo['cmdline']))
    print_('started', started)

    cpu_tot_time = datetime.timedelta(seconds=sum(pinfo['cpu_times']))
    cpu_tot_time = "%s:%s.%s" % (
        cpu_tot_time.seconds // 60 % 60,
        str((cpu_tot_time.seconds % 60)).zfill(2),
        str(cpu_tot_time.microseconds)[:2])
    print_('cpu-tspent', cpu_tot_time)
    print_('cpu-times', str_ntuple(pinfo['cpu_times']))
    if hasattr(proc, "cpu_affinity"):
        print_("cpu-affinity", pinfo["cpu_affinity"])
    if hasattr(proc, "cpu_num"):
        print_("cpu-num", pinfo["cpu_num"])

    print_('memory', str_ntuple(pinfo['memory_info'], convert_bytes=True))
    print_('memory %', round(pinfo['memory_percent'], 2))
    print_('user', pinfo['username'])
    if psutil.POSIX:
        print_('uids', str_ntuple(pinfo['uids']))
    if psutil.POSIX:
        print_('uids', str_ntuple(pinfo['uids']))
    if psutil.POSIX:
        print_('terminal', pinfo['terminal'] or '')

    print_('status', pinfo['status'])
    print_('nice', pinfo['nice'])
    if hasattr(proc, "ionice"):
        try:
            ionice = proc.ionice()
        except psutil.Error:
            pass
        else:
            if psutil.WINDOWS:
                print_("ionice", ionice)
            else:
                print_("ionice", "class=%s, value=%s" % (
                    str(ionice.ioclass), ionice.value))

    print_('num-threads', pinfo['num_threads'])
    if psutil.POSIX:
        print_('num-fds', pinfo['num_fds'])
    if psutil.WINDOWS:
        print_('num-handles', pinfo['num_handles'])

    if 'io_counters' in pinfo:
        print_('I/O', str_ntuple(pinfo['io_counters'], convert_bytes=True))
    if 'num_ctx_switches' in pinfo:
        print_("ctx-switches", str_ntuple(pinfo['num_ctx_switches']))
    if pinfo['children']:
        template = "%-6s %s"
        print_("children", template % ("PID", "NAME"))
        for child in pinfo['children']:
            try:
                print_('', template % (child.pid, child.name()))
            except psutil.AccessDenied:
                print_('', template % (child.pid, ""))
            except psutil.NoSuchProcess:
                pass

    if pinfo['open_files']:
        print_('open-files', 'PATH')
        for i, file in enumerate(pinfo['open_files']):
            if not verbose and i >= NON_VERBOSE_ITERATIONS:
                print_("", "[...]")
                break
            print_('', file.path)
    else:
        print_('open-files', '')

    if pinfo['connections']:
        template = '%-5s %-25s %-25s %s'
        print_('connections',
               template % ('PROTO', 'LOCAL ADDR', 'REMOTE ADDR', 'STATUS'))
        for conn in pinfo['connections']:
            if conn.type == socket.SOCK_STREAM:
                type = 'TCP'
            elif conn.type == socket.SOCK_DGRAM:
                type = 'UDP'
            else:
                type = 'UNIX'
            lip, lport = conn.laddr
            if not conn.raddr:
                rip, rport = '*', '*'
            else:
                rip, rport = conn.raddr
            print_('', template % (
                type,
                "%s:%s" % (lip, lport),
                "%s:%s" % (rip, rport),
                conn.status))
    else:
        print_('connections', '')

    if pinfo['threads'] and len(pinfo['threads']) > 1:
        template = "%-5s %12s %12s"
        print_('threads', template % ("TID", "USER", "SYSTEM"))
        for i, thread in enumerate(pinfo['threads']):
            if not verbose and i >= NON_VERBOSE_ITERATIONS:
                print_("", "[...]")
                break
            print_('', template % thread)
        print_('', "total=%s" % len(pinfo['threads']))
    else:
        print_('threads', '')

    if hasattr(proc, "rlimit"):
        res_names = [x for x in dir(psutil) if x.startswith("RLIMIT")]
        resources = []
        for res_name in res_names:
            try:
                soft, hard = proc.rlimit(getattr(psutil, res_name))
            except psutil.AccessDenied:
                pass
            else:
                resources.append((res_name, soft, hard))
        if resources:
            template = "%-12s %15s %15s"
            print_("res-limits", template % ("RLIMIT", "SOFT", "HARD"))
            for res_name, soft, hard in resources:
                if soft == psutil.RLIM_INFINITY:
                    soft = "infinity"
                if hard == psutil.RLIM_INFINITY:
                    hard = "infinity"
                print_('', template % (
                    RLIMITS_MAP.get(res_name, res_name), soft, hard))

    if hasattr(proc, "environ") and pinfo['environ']:
        template = "%-25s %s"
        print_("environ", template % ("NAME", "VALUE"))
        for i, k in enumerate(sorted(pinfo['environ'])):
            if not verbose and i >= NON_VERBOSE_ITERATIONS:
                print_("", "[...]")
                break
            print_("", template % (k, pinfo['environ'][k]))

    if pinfo.get('memory_maps', None):
        template = "%-8s %s"
        print_("mem-maps", template % ("RSS", "PATH"))
        maps = sorted(pinfo['memory_maps'], key=lambda x: x.rss, reverse=True)
        for i, region in enumerate(maps):
            if not verbose and i >= NON_VERBOSE_ITERATIONS:
                print_("", "[...]")
                break
            print_("", template % (bytes2human(region.rss), region.path))


if __name__ == '__main__':
    parser = argparse.ArgumentParser(
        description="печать информации о процессе")
    parser.add_argument("pid", type=int, help="process pid", nargs='?')
    parser.add_argument('--verbose', '-v', action='store_true',
                        help="дополнительная информация")
    args = parser.parse_args()
    run(args.pid, args.verbose)

Использовать можно так $python3 test.py pid. Если pid не передан, то выводит подробную информацию о собственном процессе.

Вывод сценария:

$ python3 test.py
pid           4600
name          chrome
parent        4554 (bash)
exe           /opt/google/chrome/chrome
cwd           /home/user
cmdline       /opt/google/chrome/chrome
started       2016-09-19 11:12
cpu-tspent    27:27.68
cpu-times     user=8914.32, system=3530.59,
              children_user=1.46, children_system=1.31
cpu-affinity  [0, 1, 2, 3, 4, 5, 6, 7]
memory        rss=520.5M, vms=1.9G, shared=132.6M, text=95.0M, lib=0B,
              data=816.5M, dirty=0B
memory %      3.26
user          user
uids          real=1000, effective=1000, saved=1000
uids          real=1000, effective=1000, saved=1000
[...]
children      PID    NAME
              4605   cat
              4606   cat
              4609   chrome
              4669   chrome
open-files    PATH
              /opt/google/chrome/icudtl.dat
              /opt/google/chrome/snapshot_blob.bin
              /opt/google/chrome/natives_blob.bin
              /opt/google/chrome/chrome_100_percent.pak
              [...]
connections   PROTO LOCAL ADDR            REMOTE ADDR               STATUS
              UDP   10.0.0.3:3693         *:*                       NONE
              TCP   10.0.0.3:55102        172.217.22.14:443         ESTABLISHED
              UDP   10.0.0.3:35172        *:*                       NONE
              TCP   10.0.0.3:32922        172.217.16.163:443        ESTABLISHED
              [...]
threads       TID              USER          SYSTEM
              11795             0.7            1.35
              11796            0.68            1.37
              15887            0.74            0.03
              19055            0.77            0.01
              [...]
              total=47
res-limits    RLIMIT                     SOFT       HARD
              virtualmem             infinity   infinity
              coredumpsize                  0   infinity
              cputime                infinity   infinity
              datasize               infinity   infinity
              [...]
mem-maps      RSS      PATH
              381.4M   [anon]
              62.8M    /opt/google/chrome/chrome
              15.8M    /home/user/.config/google-chrome/Default/History
              6.6M     /home/user/.config/google-chrome/Default/Favicons
              [...]