Как ограничить потребление I/O процессов Python (возможно, используя ионизацию)?

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

Возможна одна возможность ionice. Существуют ли какие-либо существующие пакеты Python для вызова ionice (Google ничего не обнаружил)? Нетрудно написать код, чтобы просто запустить команду ionice; но я бы предпочел не писать код, который кто-то еще написал/протестировал; иногда есть тонкие случаи кросс и т.д. И есть ли лучший способ ограничить потребление I/O?

справочная страница для ионики предполагает, что значение ionice может зависеть от значения nice, но запуск этого Python 2.6 script, как представляется, опровергает это, даже для дочерних процессов, где наследуется значение nice:

#!/usr/bin/env python

import os
import multiprocessing

def print_ionice(name):
    print '*** ', name, ' ***'
    os.system("echo -n 'nice: '; nice")
    os.system("echo -n 'ionice: '; ionice -p%d" % os.getpid())

for niced in (None, 19):
    if niced: os.nice(niced)
    print '**** niced to: ', niced, ' ****'
    print_ionice('parent')
    subproc = multiprocessing.Process(target=print_ionice, args=['child'])
    subproc.start()
    subproc.join()

Что имеет следующий вывод:

$ uname -as
Linux x.fake.org 2.6.27-11-server #1 SMP Thu Jan 29 20:13:12 UTC 2009 x86_64 GNU/Linux
$ ./foo.py
**** niced to:  None  ****
***  parent  ***
nice: 0
ionice: none: prio 4
***  child  ***
nice: 0
ionice: none: prio 4
**** niced to:  19  ****
***  parent  ***
nice: 19
ionice: none: prio 4
***  child  ***
nice: 19
ionice: none: prio 4

Ответы

Ответ 1

psutil раскрывает эту функциональность (python 2.4 → 3.2):

import psutil, os
p = psutil.Process(os.getpid())
p.ionice(psutil.IOPRIO_CLASS_IDLE)

Кроме того, начиная с Python 3.3, это также будет доступно в python stdlib: http://bugs.python.org/issue10784

Ответ 2

Hm.

В качестве указателя начала вы должны найти, что syscall число - это системные вызовы ioprio_set и ioprio_get в вашем ядре. Я предлагаю вам проверить /usr/include/asm/unistd_32.h или /usr/include/asm/unistd_64.h, в зависимости от вашей арки ядра; если нет, начните с предложения страницы syscall(2) man, которая должна быть /usr/include/sys/syscall.h и включает в себя ваш путь вниз.

Учитывая это, вы должны использовать ctypes, à la:

def ioprio_set(which, who, ioprio):
    rc= ctypes.CDLL('libc.so.6').syscall(289, which, who, ioprio)
    # some error checking goes here, and possibly exception throwing

Что это, более или менее. Удачи:)

Ответ 3

Почему бы не запустить какие-либо процессы на ионизацию на них (т.е. запустить их с помощью ионитов), а не самим ионитом? Кажется, все намного чище.