resource – システムリソース管理

目的:Unix プログラムのシステムリソースリミットを管理する
利用できるバージョン:1.5.2

resource モジュールの関数は、プロセスが消費する現在のシステムリソースを調べて、プログラムがシステム上でどのぐらいの負荷を与えるかを制御するためにリミットを設けます。

現在の使用状況

カレントプロセスやその子プロセスが使用するリソースを調べるには getrusage() を使用してください。返り値は現在のシステムの状態に基づく複数のリソース値を含むデータです。

Note

この記事では全てのリソース値を紹介しません。完全なリストは 標準ライブラリドキュメント を参照してください。

import resource
import time

usage = resource.getrusage(resource.RUSAGE_SELF)

for name, desc in [
    ('ru_utime', 'User time'),
    ('ru_stime', 'System time'),
    ('ru_maxrss', 'Max. Resident Set Size'),
    ('ru_ixrss', 'Shared Memory Size'),
    ('ru_idrss', 'Unshared Memory Size'),
    ('ru_isrss', 'Stack Size'),
    ('ru_inblock', 'Block inputs'),
    ('ru_oublock', 'Block outputs'),
    ]:
    print '%-25s (%-10s) = %s' % (desc, name, getattr(usage, name))

テストプログラムはとても単純なので、あまりリソースを消費しません。

$ python resource_getrusage.py
User time                 (ru_utime  ) = 0.009676
System time               (ru_stime  ) = 0.005418
Max. Resident Set Size    (ru_maxrss ) = 3895296
Shared Memory Size        (ru_ixrss  ) = 0
Unshared Memory Size      (ru_idrss  ) = 0
Stack Size                (ru_isrss  ) = 0
Block inputs              (ru_inblock) = 0
Block outputs             (ru_oublock) = 1

リソースリミット

現在の実際の使用状況とは別に、アプリケーションに与えられた リミット を調べて変更できます。

import resource

for name, desc in [
    ('RLIMIT_CORE', 'core file size'),
    ('RLIMIT_CPU',  'CPU time'),
    ('RLIMIT_FSIZE', 'file size'),
    ('RLIMIT_DATA', 'heap size'),
    ('RLIMIT_STACK', 'stack size'),
    ('RLIMIT_RSS', 'resident set size'),
    ('RLIMIT_NPROC', 'number of processes'),
    ('RLIMIT_NOFILE', 'number of open files'),
    ('RLIMIT_MEMLOCK', 'lockable memory address'),
    ]:
    limit_num = getattr(resource, name)
    soft, hard = resource.getrlimit(limit_num)
    print 'Maximum %-25s (%-15s) : %20s %20s' % (desc, name, soft, hard)

それぞれのリミットの返り値は、現在の設定の ソフト リミットとオペレーティングシステムの ハード リミットを含むタプルです。

$ python resource_getrlimit.py
Maximum core file size            (RLIMIT_CORE    ) :                    0  9223372036854775807
Maximum CPU time                  (RLIMIT_CPU     ) :  9223372036854775807  9223372036854775807
Maximum file size                 (RLIMIT_FSIZE   ) :  9223372036854775807  9223372036854775807
Maximum heap size                 (RLIMIT_DATA    ) :  9223372036854775807  9223372036854775807
Maximum stack size                (RLIMIT_STACK   ) :              8388608             67104768
Maximum resident set size         (RLIMIT_RSS     ) :  9223372036854775807  9223372036854775807
Maximum number of processes       (RLIMIT_NPROC   ) :                  709                 1064
Maximum number of open files      (RLIMIT_NOFILE  ) :                 2560  9223372036854775807
Maximum lockable memory address   (RLIMIT_MEMLOCK ) :  9223372036854775807  9223372036854775807

そのリミットは setrlimit() で変更できます。例えば、1つのプロセスがオープンできるファイル数を制御するために RLIMIT_NOFILE をより小さなソフトリミットを使用するように変更できます。

import resource
import os

soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
print 'Soft limit starts as  :', soft

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

soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
print 'Soft limit changed to :', soft

random = open('/dev/random', 'r')
print 'random has fd =', random.fileno()
try:
    null = open('/dev/null', 'w')
except IOError, err:
    print err
else:
    print 'null has fd =', null.fileno()
$ python resource_setrlimit_nofile.py
Soft limit starts as  : 2560
Soft limit changed to : 4
random has fd = 3
[Errno 24] Too many open files: '/dev/null'

それは1つのプロセスが消費する CPU 時間に対して、多くの時間を費やさないように制限するのにも便利です。そのプロセスが割り当てられた CPU 時間を実行したときに SIGXCPU シグナルを送信します。

import resource
import sys
import signal
import time

# CPU 時間リミットが実行されたときに
# 通知するシグナルハンドラを設定する
def time_expired(n, stack):
    print 'EXPIRED :', time.ctime()
    raise SystemExit('(time ran out)')

signal.signal(signal.SIGXCPU, time_expired)

# CPU 時間リミットを調整する
soft, hard = resource.getrlimit(resource.RLIMIT_CPU)
print 'Soft limit starts as  :', soft

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

soft, hard = resource.getrlimit(resource.RLIMIT_CPU)
print 'Soft limit changed to :', soft
print

# 意味のない処理で CPU 時間を消費する
print 'Starting:', time.ctime()
for i in range(200000):
    for i in range(200000):
        v = i * i

# この処理は実行されない
print 'Exiting :', time.ctime()

普通はシグナルハンドラがオープンされた全てのファイルをフラッシュしてからクローズします。しかし、このサンプルはただメッセージを表示して終了します。

$ python resource_setrlimit_cpu.py
Soft limit starts as  : 9223372036854775807
Soft limit changed to : 1

Starting: Sun Feb 17 11:33:12 2013
EXPIRED : Sun Feb 17 11:33:13 2013
(time ran out)

See also

resource
本モジュールの標準ライブラリドキュメント
signal
シグナルハンドラ登録の詳細
Bookmark and Share