resource - Gestione delle Risorse di Sistema

Scopo: Gestisce i limiti delle risorse di sistema per un programma Unix

Le funzioni in resource rilevano le risorse del sistema corrente consumate da un processo, e pongono limiti su di esse per controllare quanto carico un programma può imporre a un sistema.

Utilizzo Corrente

Si usi getrusage() per rilevare le risorse usate dal processo corrente e/o dai suoi figli. Il valore di ritorno è una struttura dati contenente parecchie metriche di risorse basate sullo stato corrente del sistema.

Non tutti i valori delle risorse raccolti sono qui visualizzati. Si faccia riferimento alla documentazione della libreria standard per resource per un elenco più completo
# resource_getrusage.py

import resource


RESOURCES = [
    ('ru_utime', 'Tempo utente'),
    ('ru_stime', 'Tempo sistema'),
    ('ru_maxrss', 'Dimensione massima memoria\nfisica'
                  ' mappata dal processo     '),
    ('ru_ixrss', 'Dimensione memoria condivisa '),
    ('ru_idrss', 'Dimensione memoria non condivisa'),
    ('ru_isrss', 'Dimensione dello stack'),
    ('ru_inblock', 'Blocchi input'),
    ('ru_oublock', 'Blocchi output'),
]

usage = resource.getrusage(resource.RUSAGE_SELF)

for name, desc in RESOURCES:
    print('{:<32} ({:<10}) = {}'.format(
        desc, name, getattr(usage, name)))

Il programma di test è estremamente semplice, quindi non usa molte risorse.

$ python3 resource_getrusage.py

Tempo utente                     (ru_utime  ) = 0.021376
Tempo sistema                    (ru_stime  ) = 0.0
Dimensione massima memoria
fisica mappata dal processo      (ru_maxrss ) = 10016
Dimensione memoria condivisa     (ru_ixrss  ) = 0
Dimensione memoria non condivisa (ru_idrss  ) = 0
Dimensione dello stack           (ru_isrss  ) = 0
Blocchi input                    (ru_inblock) = 40
Blocchi output                   (ru_oublock) = 0

Limiti delle Risorse

Oltre al reale utilizzo, è possibile verificare i limit imposti all'applicazione, per puoi modificarli.

# resource_getrlimit.py

import resource


LIMITS = [
    ('RLIMIT_CORE', 'Dimensione file core'),
    ('RLIMIT_CPU', 'Tempo CPU'),
    ('RLIMIT_FSIZE', 'Dimensione file'),
    ('RLIMIT_DATA', 'Dimensione heap '),
    ('RLIMIT_STACK', 'Dimensione stack '),
    ('RLIMIT_RSS', 'Dimensione massima memoria\n'
                   'fisica mappata del processo     '),
    ('RLIMIT_NPROC', 'Numero di processi'),
    ('RLIMIT_NOFILE', 'Numero di file aperti'),
    ('RLIMIT_MEMLOCK', 'Indirizzo di memoria bloccabile'),
]

print('Limit delle risorse (soft/hard):')
for name, desc in LIMITS:
    limit_num = getattr(resource, name)
    soft, hard = resource.getrlimit(limit_num)
    print('{:<32} {}/{}'.format(desc, soft, hard))

Il valore di ritorno per ciascun limite è una tupla che contiene il limite soft imposto dalla configurazione corrente e il limite hard imposto dal sistema operativo.

Un limite hard può essere alzato solo da root e qualsiasi processo lo può abbassare. Un limite soft può essere cambiato da un processo in qualunque momento
$ python3 resource_getrlimit.py

Limit delle risorse (soft/hard):
Dimensione file core             0/-1
Tempo CPU                        -1/-1
Dimensione file                  -1/-1
Dimensione heap                  -1/-1
Dimensione stack                 8388608/-1
Dimensione massima memoria
fisica mappata del processo      -1/-1
Numero di processi               31345/31345
Numero di file aperti            1048576/1048576
Indirizzo di memoria bloccabile  67108864/67108864

I limiti possono essere cambiati con setrlimit().

# resource_setrlimit_nofile.py

import resource


soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
print('Limite soft inizia come  :', soft)

resource.setrlimit(resource.RLIMIT_NOFILE, (4, hard))

soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
print('Limite soft modificato in:', soft)

random = open('/dev/random', 'r')
print('random ha fd =', random.fileno())
try:
    null = open('/dev/null', 'w')
except IOError as err:
    print(err)
else:
    print('null ha fd =', null.fileno())

Questo esempio usa RLIMIT_NOFILE per controllare il numero di file aperti consentiti, modificandolo con un limite soft inferiore rispetto al predefinito.

$ python3 resource_setrlimit_nofile.py

Limite soft inizia come  : 1048576
Limite soft modificato in: 4
random ha fd = 3
[Errno 24] Too many open files: '/dev/null'

Può anche essere utile limitare l'ammontare di tempo di CPU che un processo può consumare, per evitarne di utilizzarne troppo. Quando il processo supera il limite di tempo allocato, invia un segnale SIGXCPU.

# resource_setrlimit_cpu.py

import resource
import signal
import time


# Imposta un gestore di segnale per notificare
# quando il tempo si esaurisce
def time_expired(n, stack):
    print('SCADUTO :', time.ctime())
    raise SystemExit('(tempo scaduto)')


signal.signal(signal.SIGXCPU, time_expired)

# Adjust the CPU time limit
soft, hard = resource.getrlimit(resource.RLIMIT_CPU)
print('Limite soft inizia come  :', soft)

resource.setrlimit(resource.RLIMIT_CPU, (1, hard))

soft, hard = resource.getrlimit(resource.RLIMIT_CPU)
print('Limite soft modificato in:', soft)
print()

# Consume some CPU time in a pointless exercise
print('Partenza:', time.ctime())
for i in range(200000):
    for i in range(200000):
        v = i * i

# We should never make it this far
print('Uscita :', time.ctime())

Normalmente un gestore di segnale finisce di scrivere tutti i file aperti e li chiude, ma in questo caso stampa semplicemente un messaggio ed esce.

$ python3 resource_setrlimit_cpu.py

Limite soft inizia come  : -1
Limite soft modificato in: 1

Partenza: Thu Jun  3 09:15:32 2021
SCADUTO : Thu Jun  3 09:15:33 2021
(tempo scaduto)

Vedere anche:

resource
La documentazione della libreria standard per questo modulo.
signal
Per dettagli sulla registrazione dei gestori di segnale.