Материал содержит описание функций модуля psutil
с примерами, которые возвращают статистику использования жесткого диска, такую как: разделы диска, использование диска для конкретного раздела, статистика дискового ввода-вывода.
psutil.disk_partitions()
все смонтированные разделы диска,psutil.disk_usage()
статистика использования диска для раздела,psutil.disk_io_counters()
общесистемная статистика дискового ввода-вывода;psutil.disk_partitions(all=False)
:Функция psutil.disk_partitions()
возвращает все смонтированные разделы диска в виде списка именованных кортежей, включая устройство, точку монтирования и тип файловой системы, аналогично команде df
в UNIX.
Если для аргумента all
установлено значение False
, то функция будет пытаться различать и возвращать только физические устройства (например, жесткие диски, приводы компакт-дисков, USB-накопители) и игнорировать все остальные (например, память, дубликаты, недоступные файловые системы). Обратите внимание, что это поведение может быть не надежным в некоторых системах (например, в BSD этот параметр игнорируется).
Возвращает список именованных кортежей со следующими полями:
device
: путь к устройству (например, "/dev/hda1"
). В Windows это буква диска (например, "C:\\"
).mountpoint
: путь к точке монтирования (например, "/"
). В Windows это буква диска (например, "C:\\"
).fstype
: файловая система раздела (например, "ext3"
в UNIX или "NTFS"
в Windows).opts
: строка, разделенная запятыми, указывающая различные варианты подключения для диска/раздела (в зависимости от платформы).maxfile
: максимальная длина, которую может иметь имя файла.maxpath
: максимальная длина, которую может иметь имя пути (имя каталога + имя базового файла).>>> import psutil >>> psutil.disk_partitions() # [ # sdiskpart(device='/dev/sda3', mountpoint='/', fstype='ext4', # opts='rw,errors=remount-ro', maxfile=255, maxpath=4096), # sdiskpart(device='/dev/sda7', mountpoint='/home', fstype='ext4', # opts='rw', maxfile=255, maxpath=4096) # ]
psutil.disk_usage(path)
:Функция psutil.disk_usage()
возвращает статистику использования диска для раздела, содержащего указанный путь path
, в виде именованного кортежа, включая общее, используемое и свободное пространство, выраженное в байтах, а также использование в процентах.
Если путь не существует, то возникает исключение OSError
.
Дополнительно смотрите похожую функцию стандартной библиотеки
shutil.disk_usage()
.
>>> import psutil >>> psutil.disk_usage('/') # sdiskusage(total=21378641920, used=4809781248, free=15482871808, percent=22.5)
Примечание. Системы UNIX обычно резервирует 5% всего дискового пространства для пользователя
root
. Поляtotal
иused
в UNIX относятся к общему и используемому пространству, тогда какfree
представляет пространство, доступное для пользователя, аpercent
представляет использование пользователем. Вот почему значениеpercent
может выглядеть на 5% больше, чем ожидается. Также обратите внимание, что оба значения соответствуют команде bash -df
.
psutil.disk_io_counters(perdisk=False, nowrap=True)
:Функция psutil.disk_io_counters()
возвращает общесистемную статистику дискового ввода-вывода в виде именованного кортежа, включающего следующие поля:
read_count
: количество считываний;write_count
: количество записей;read_bytes
: количество прочитанных байт;write_bytes
: количество записанных байт.Поля, специфичные для конкретной платформы:
read_time
: (все, кроме NetBSD и OpenBSD) время, затраченное на чтение с диска (в миллисекундах)write_time
: (все, кроме NetBSD и OpenBSD) время, затраченное на запись на диск (в миллисекундах)busy_time
: (Linux, FreeBSD) время, затраченное на фактический ввод-вывод (in milliseconds)read_merged_count
(Linux): количество объединенных чтений (системный вызов iostats
)write_merged_count
(Linux): количество объединенных записей (системный вызов iostats
)Если аргумент perdisk
имеет значение True
, то возвращает ту же информацию для каждого физического диска, установленного в системе, в виде словаря с именами разделов в качестве ключей и именованным кортежем, описанным выше, в качестве значений.
В некоторых системах, таких как Linux, в очень загруженных или долгоживущих системах, числа, возвращаемые ядром, могут переполняться и переноситься (перезапускаться с нуля). Если аргумент nowrap
имеет значение True
, то модуль psutil
обнаружит и скорректирует эти числа при вызовах функций и добавит "старое значение" к "новому значению", чтобы возвращаемые числа всегда увеличивались или оставались неизменными, но никогда не уменьшались.
Для аннулирования кеша nowrap
можно использовать psutil.disk_io_counters.cache_clear()
. В Windows, чтобы включить счетчики ввода-вывода, сначала может потребоваться выполнить команду diskperf -y
. На бездисковых машинах, если perdisk
имеет значение True
, то эта функция вернет None
или пустой словарь {}
.
>>> import psutil >>> psutil.disk_io_counters() # sdiskio(read_count=8141, write_count=2431, read_bytes=290203, # write_bytes=537676, read_time=5868, write_time=94922) >>> psutil.disk_io_counters(perdisk=True) # { # 'sda1': sdiskio(read_count=920, write_count=1, read_bytes=2933248, # write_bytes=512, read_time=6016, write_time=4), # 'sda2': sdiskio(read_count=18707, write_count=8830, read_bytes=6060, # write_bytes=3443, read_time=24585, write_time=1572), # 'sdb1': sdiskio(read_count=161, write_count=0, read_bytes=786432, # write_bytes=0, read_time=44, write_time=0) # }
Примечание: возможно, сначала потребуется выполнить команду Windows
diskperf -y
, иначе эта функция не найдет ни одного диска.
import os import sys import psutil from psutil._common import bytes2human def main(): templ = "%-17s %8s %8s %8s %5s%% %9s %s" print(templ % ("Device", "Total", "Used", "Free", "Use ", "Type", "Mount")) for part in psutil.disk_partitions(all=False): if os.name == 'nt': if 'cdrom' in part.opts or part.fstype == '': # пропускаем приводы cd-rom, в которых нет диска; # они могут вызвать ошибку графического интерфейса # Windows для неготового раздела или просто зависнуть continue usage = psutil.disk_usage(part.mountpoint) print(templ % ( part.device, bytes2human(usage.total), bytes2human(usage.used), bytes2human(usage.free), int(usage.percent), part.fstype, part.mountpoint)) if __name__ == '__main__': sys.exit(main())
Вывод сценария:
$ python3 test.py Device Total Used Free Use % Type Mount /dev/sdb3 18.9G 14.7G 3.3G 77% ext4 / /dev/sda6 345.9G 83.8G 244.5G 24% ext4 /home /dev/sda1 296.0M 43.1M 252.9M 14% vfat /boot/efi /dev/sda2 600.0M 312.4M 287.6M 52% fuseblk /media/Recovery
Данный пример представляет собой клон утилиты Linux iotop
, которая показывает в реальном времени статистику дискового ввода-вывода.
curses
.import sys import time try: import curses except ImportError: sys.exit('Платформа не поддерживается') import psutil from psutil._common import bytes2human win = curses.initscr() lineno = 0 def printl(line, highlight=False): """Тонкая обертка вокруг `curses`.""" global lineno try: if highlight: line += " " * (win.getmaxyx()[1] - len(line)) win.addstr(lineno, 0, line, curses.A_REVERSE) else: win.addstr(lineno, 0, line, 0) except curses.error: lineno = 0 win.refresh() raise else: lineno += 1 def poll(interval): """Расчет использования операций ввода-вывода, сравнив данные до и после интервала `interval` (аргумент функции). Возвращает кортеж, включающий все запущенные в данный момент процессы, отсортированные по активности ввода-вывода и общей активности дискового ввода-вывода. """ # получаем список всех процессов и счетчиков ввода-вывода с диска procs = [p for p in psutil.process_iter()] for p in procs[:]: try: p._before = p.io_counters() except psutil.Error: procs.remove(p) continue disks_before = psutil.disk_io_counters() # немного спим time.sleep(interval) # затем снова вытаскиваем ту же информацию for p in procs[:]: with p.oneshot(): try: p._after = p.io_counters() p._cmdline = ' '.join(p.cmdline()) if not p._cmdline: p._cmdline = p.name() p._username = p.username() except (psutil.NoSuchProcess, psutil.ZombieProcess): procs.remove(p) disks_after = psutil.disk_io_counters() # рассчитываем результаты, сравнив данные до и после `interval` for p in procs: p._read_per_sec = p._after.read_bytes - p._before.read_bytes p._write_per_sec = p._after.write_bytes - p._before.write_bytes p._total = p._read_per_sec + p._write_per_sec disks_read_per_sec = disks_after.read_bytes - disks_before.read_bytes disks_write_per_sec = disks_after.write_bytes - disks_before.write_bytes # сортируем процессы по общему объему ввода-вывода с диска, # более интенсивные будут первыми processes = sorted(procs, key=lambda p: p._total, reverse=True) return (processes, disks_read_per_sec, disks_write_per_sec) def refresh_window(procs, disks_read, disks_write): """Вывод результатов на экран с помощью curses.""" curses.endwin() templ = "%-5s %-7s %11s %11s %s" win.erase() disks_tot = "Total DISK READ: %s | Total DISK WRITE: %s" \ % (bytes2human(disks_read), bytes2human(disks_write)) printl(disks_tot) header = templ % ("PID", "USER", "DISK READ", "DISK WRITE", "COMMAND") printl(header, highlight=True) for p in procs: line = templ % ( p.pid, p._username[:7], bytes2human(p._read_per_sec), bytes2human(p._write_per_sec), p._cmdline) try: printl(line) except curses.error: break win.refresh() def setup(): curses.start_color() curses.use_default_colors() for i in range(0, curses.COLORS): curses.init_pair(i + 1, i, -1) curses.endwin() win.nodelay(1) def tear_down(): win.keypad(0) curses.nocbreak() curses.echo() curses.endwin() if __name__ == '__main__': setup() try: interval = 0 while True: if win.getch() == ord('q'): break args = poll(interval) refresh_window(*args) lineno = 0 interval = 0.5 time.sleep(interval) except (KeyboardInterrupt, SystemExit): pass finally: tear_down()
Вывод сценария:
$ python3 test.py Total DISK READ: 0.00 B/s | Total DISK WRITE: 472.00 K/s PID USER DISK READ DISK WRITE COMMAND 13155 giampao 0.00 B/s 428.00 K/s /usr/bin/google-chrome-beta 3260 giampao 0.00 B/s 0.00 B/s bash 3779 giampao 0.00 B/s 0.00 B/s gnome-session --session=ubuntu 3830 giampao 0.00 B/s 0.00 B/s /usr/bin/dbus-launch 3831 giampao 0.00 B/s 0.00 B/s //bin/dbus-daemon --fork --print-pid 5 3841 giampao 0.00 B/s 0.00 B/s /usr/lib/at-spi-bus-launcher 3845 giampao 0.00 B/s 0.00 B/s /bin/dbus-daemon 3848 giampao 0.00 B/s 0.00 B/s /usr/lib/at-spi2-core/at-spi2-registryd 3862 giampao 0.00 B/s 0.00 B/s /usr/lib/gnome-settings-daemon