Weitere ähnliche Inhalte Ähnlich wie Subprocess no susume (20) Mehr von Makoto Kishimoto (9) Subprocess no susume2. 最近書いているプログラム
class Ref:
def __init__(self):
self.v = None
def gps(i, n, z, v):
i.v = 1
while i.v <= n():
z.v = v()
i.v += 1
return 1
3. i, p, a, z = Ref(), Ref(), Ref(), Ref()
m = 46
i.v = gps(i, lambda: (i.v == 0 and [-1] or [i.v])[0], p,
lambda: (i.v == 1 and [1] or
[(gps(a, lambda: i.v, z,
lambda: (a.v == 1 and [1] or
[((i.v % a.v == 0 and a.v < i.v)
and [0] or [z.v])[0]])[0]) == z.v
and [(p.v < m and [p.v + 1]
or [i.v * gps(a, lambda: 1, i, lambda: -1)])[0]]
or [p.v])[0]])[0])
4. 本題
● 標準ライブラリの subprocess モジュールを
使いましょう、という話
● おことわり: Windows でも使えるライブラリですが、
発表者が使っていないため Unix の話しかしません
● 深い話(背景とか)は(Rubyですが)以下の
田中哲さんの発表資料を見ましょう
– Rubyとプロセス spawnについて
http://www.a-k-r.org/pub/spawn-2009-04.pdf
– open3 のはなし
http://www.a-k-r.org/pub/tokyo-rubykaigi-03-akr-2010.pdf
5. subprocess モジュールとは
● Python 2.6 で標準ライブラリに導入
● Python 3 で commands モジュール等は削除
● 他にも os.system, os.spawn, os.popen[234],
popen2 モジュールの機能を代替する
● 謎の commands.getstatus
(ファイルを指定して ls -ld の結果を返す)
6. ちょっとだけ背景
● fork と exec
● Unix の特徴とも言われる
– プロセスのクローンと、プログラムのオーバレイに分けた
– fork → なんかする → exec / すごくシンプルになった
● 難点(昔) – 重い
– コピーオンライト/vfork で解決?
● 変な応用例: DalvikVM – fork だけで exec しない
● 現代の難点
● マルチスレッドとの相性 - すごく悪い
7. subprocess.Popen
class subprocess.Popen(args, bufsize=-1,
executable=None, stdin=None,
stdout=None, stderr=None,
preexec_fn=None, close_fds=True,
shell=False, cwd=None, env=None,
universal_newlines=False,
startupinfo=None, creationflags=0,
restore_signals=True,
start_new_session=False, pass_fds=())
8. なんでこんなキッチンシンクに?
● キッチンシンク←なんでもかんでも放り込むたとえ
● fork と exec の間に「いろいろできる」(リダイレクトと
か)のを、全部引数で指示するから
● 計算機を仮想化する単位であるプロセスを切り離す
作業だから、仮想化してあるものをここで全部(ファイ
ルハンドラとか)面倒を見なきゃならないから
10. ユースケース
● 標準ライブラリのドキュメントと PEP 324 から
● 以降は from subprocess import * してある
前提で
12. パイプラインありの展開
result=`dmesg | grep hda`
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()
result = p2.communicate()[0]
(コマンド文字列インジェクションの心配がないなら)
result = check_output("dmesg | grep hda", shell=True)
13. os.system の代替
st = os.system(”cmd arg”)
st = call(”cmd”, ”arg”, shell=True)
(シェル経由で呼ぶのはsystemというAPIの特
徴。シェルが必要ないなら使わない)
14. os.spawn の代替
pid = os.spawnlp(os.P_NOWAIT, "/bin/cmd", "cmd", "arg")
pid = Popen(["/bin/cmd", "arg"]).pid
ret = os.spawnlp(os.P_WAIT, "/bin/cmd", "cmd", "arg")
ret = call(["/bin/cmd", "arg"])
os.spawnvp(os.P_NOWAIT, path, args)
Popen([path] + args[1:])
os.spawnlpe(os.P_NOWAIT, "/bin/cmd", "cmd", "arg", env)
Popen(["/bin/cmd", "arg"], env={"PATH": "/usr/bin"})
15. os.popen2
(child_stdin, child_stdout) =
os.popen2(cmd, mode, bufsize)
p = Popen(cmd, shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE, close_fds=True)
(child_stdin, child_stdout) = (p.stdin, p.stdout)
16. os.popen3
(child_stdin,
child_stdout,
child_stderr) = os.popen3(cmd, mode, bufsize)
p = Popen(cmd, shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE,
stderr=PIPE, close_fds=True)
(child_stdin,
child_stdout,
child_stderr) = (p.stdin, p.stdout, p.stderr)
17. os.popen4
(child_stdin, child_stdout_and_stderr) =
os.popen4(cmd, mode, bufsize)
p = Popen(cmd, shell=True, bufsize=bufsize,
stdin=PIPE, stdout=PIPE,
stderr=STDOUT, close_fds=True)
(child_stdin, child_stdout_and_stderr) =
(p.stdin, p.stdout)
18. popen2 モジュール
(child_stdout, child_stdin) =
popen2.popen2("somestring", bufsize, mode)
p = Popen(["somestring"], shell=True,
bufsize=bufsize, stdin=PIPE,
stdout=PIPE, close_fds=True)
(child_stdout, child_stdin) = (p.stdout, p.stdin)
19. まとめ
● subprocess モジュールは、サブプロセスを作る既存
の API 全てを代替する
● 全てを代替するために、subprocess の API は大
変なことになっている
● ケーススタディをマニュアルから紹介した