SlideShare ist ein Scribd-Unternehmen logo
1 von 19
Downloaden Sie, um offline zu lesen
subprocessのススメ



   岸本 誠
 (@ksmakoto)
最近書いているプログラム

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
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])
本題
●   標準ライブラリの 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
subprocess モジュールとは
●   Python 2.6 で標準ライブラリに導入
●   Python 3 で commands モジュール等は削除
●   他にも os.system, os.spawn, os.popen[234],
    popen2 モジュールの機能を代替する
●   謎の commands.getstatus
    (ファイルを指定して ls -ld の結果を返す)
ちょっとだけ背景
●   fork と exec
●   Unix の特徴とも言われる
    –   プロセスのクローンと、プログラムのオーバレイに分けた
    –   fork → なんかする → exec / すごくシンプルになった
●   難点(昔) – 重い
    –   コピーオンライト/vfork で解決?
●   変な応用例: DalvikVM – fork だけで exec しない
●   現代の難点
●   マルチスレッドとの相性 - すごく悪い
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=())
なんでこんなキッチンシンクに?
●   キッチンシンク←なんでもかんでも放り込むたとえ




●   fork と exec の間に「いろいろできる」(リダイレクトと
    か)のを、全部引数で指示するから
●   計算機を仮想化する単位であるプロセスを切り離す
    作業だから、仮想化してあるものをここで全部(ファイ
    ルハンドラとか)面倒を見なきゃならないから
ひとつ注意
preexec_fn
exec の前に実行される関数引数。なんでも指定できる
が、可能な限り余計なことはしてはいけない。英語版ドキュ
メントには赤背景で以下のように書いてある。
Warning: The preexec_fn parameter is not safe to
use in the presence of threads in your application.
The child process could deadlock before exec is
called. If you must use it, keep it trivial! Minimize
the number of libraries you call into.
これは libc に由来するスレッド絡みの制限で、実は厄介。
ユースケース
●   標準ライブラリのドキュメントと PEP 324 から

●   以降は from subprocess import * してある
    前提で
シェルスクリプトのコマンド展開

result=`ls -l myfile`

result = check_output([”ls”, ”-l”, ”myfile”])
パイプラインありの展開
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)
os.system の代替

st = os.system(”cmd arg”)

st = call(”cmd”, ”arg”, shell=True)
(シェル経由で呼ぶのはsystemというAPIの特
徴。シェルが必要ないなら使わない)
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"})
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)
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)
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)
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)
まとめ

●   subprocess モジュールは、サブプロセスを作る既存
    の API 全てを代替する
●   全てを代替するために、subprocess の API は大
    変なことになっている
●   ケーススタディをマニュアルから紹介した

Weitere ähnliche Inhalte

Was ist angesagt?

配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
TatsuyaKatayama
 
Boost.Coroutine
Boost.CoroutineBoost.Coroutine
Boost.Coroutine
melpon
 
Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理
Takeshi Arabiki
 
Continuation with Boost.Context
Continuation with Boost.ContextContinuation with Boost.Context
Continuation with Boost.Context
Akira Takahashi
 

Was ist angesagt? (20)

Mock and patch
Mock and patchMock and patch
Mock and patch
 
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
配管流路の多目的最適化OpenFOAM+OpenMDAO(第28回オープンCAE勉強会@関西)
 
ALPSチュートリアル(4) Python入門
ALPSチュートリアル(4) Python入門ALPSチュートリアル(4) Python入門
ALPSチュートリアル(4) Python入門
 
C++でHello worldを書いてみた
C++でHello worldを書いてみたC++でHello worldを書いてみた
C++でHello worldを書いてみた
 
Rの高速化
Rの高速化Rの高速化
Rの高速化
 
Goをカンストさせる話
Goをカンストさせる話Goをカンストさせる話
Goをカンストさせる話
 
emc++ chapter32
emc++ chapter32emc++ chapter32
emc++ chapter32
 
Effective modern-c++#9
Effective modern-c++#9Effective modern-c++#9
Effective modern-c++#9
 
effective modern c++ chapeter36
effective modern c++ chapeter36effective modern c++ chapeter36
effective modern c++ chapeter36
 
前期講座09
前期講座09前期講座09
前期講座09
 
JavaScript入門
JavaScript入門JavaScript入門
JavaScript入門
 
Boost.Coroutine
Boost.CoroutineBoost.Coroutine
Boost.Coroutine
 
Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理Rのデータ構造とメモリ管理
Rのデータ構造とメモリ管理
 
Continuation with Boost.Context
Continuation with Boost.ContextContinuation with Boost.Context
Continuation with Boost.Context
 
Boost tour 1.60.0 merge
Boost tour 1.60.0 mergeBoost tour 1.60.0 merge
Boost tour 1.60.0 merge
 
テーマ「最適化 その2」
テーマ「最適化 その2」テーマ「最適化 その2」
テーマ「最適化 その2」
 
Altanative macro
Altanative macroAltanative macro
Altanative macro
 
llvm入門
llvm入門llvm入門
llvm入門
 
Task
TaskTask
Task
 
Siv3Dで楽しむゲームとメディアアート開発
Siv3Dで楽しむゲームとメディアアート開発Siv3Dで楽しむゲームとメディアアート開発
Siv3Dで楽しむゲームとメディアアート開発
 

Ähnlich wie Subprocess no susume

Ruby Postgres 2009
Ruby Postgres 2009Ruby Postgres 2009
Ruby Postgres 2009
Akio Ishida
 
Python Kyoto study
Python Kyoto studyPython Kyoto study
Python Kyoto study
Naoya Inada
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
Ransui Iso
 

Ähnlich wie Subprocess no susume (20)

ひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指すひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指す
 
PHPの今とこれから2014
PHPの今とこれから2014PHPの今とこれから2014
PHPの今とこれから2014
 
Introduction of Python
Introduction of PythonIntroduction of Python
Introduction of Python
 
C-langage
C-langageC-langage
C-langage
 
Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6Lisp Tutorial for Pythonista Day 6
Lisp Tutorial for Pythonista Day 6
 
仕事で使えるシェルスクリプト
仕事で使えるシェルスクリプト仕事で使えるシェルスクリプト
仕事で使えるシェルスクリプト
 
ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。ラズパイでデバイスドライバを作ってみた。
ラズパイでデバイスドライバを作ってみた。
 
Ruby Postgres 2009
Ruby Postgres 2009Ruby Postgres 2009
Ruby Postgres 2009
 
私とOSS活動とPerl
私とOSS活動とPerl私とOSS活動とPerl
私とOSS活動とPerl
 
Coq 20100208a
Coq 20100208aCoq 20100208a
Coq 20100208a
 
Ansible2.0と実用例
Ansible2.0と実用例Ansible2.0と実用例
Ansible2.0と実用例
 
Swift 2.0 で変わったところ「後編」 #cswift
Swift 2.0 で変わったところ「後編」 #cswiftSwift 2.0 で変わったところ「後編」 #cswift
Swift 2.0 で変わったところ「後編」 #cswift
 
about DakotagUI
about DakotagUIabout DakotagUI
about DakotagUI
 
Python Kyoto study
Python Kyoto studyPython Kyoto study
Python Kyoto study
 
PHPの今とこれから 2013
PHPの今とこれから 2013PHPの今とこれから 2013
PHPの今とこれから 2013
 
メタメタプログラミングRuby
メタメタプログラミングRubyメタメタプログラミングRuby
メタメタプログラミングRuby
 
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
「Python言語」はじめの一歩 / First step of Python / 2016 Jan 12
 
Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1Lisp tutorial for Pythonista : Day 1
Lisp tutorial for Pythonista : Day 1
 
Pythonで始めるDropboxAPI
Pythonで始めるDropboxAPIPythonで始めるDropboxAPI
Pythonで始めるDropboxAPI
 
最新PHP事情 (2000年7月22日,PHPカンファレンス)
最新PHP事情 (2000年7月22日,PHPカンファレンス)最新PHP事情 (2000年7月22日,PHPカンファレンス)
最新PHP事情 (2000年7月22日,PHPカンファレンス)
 

Mehr von Makoto Kishimoto (9)

CHP survey
CHP surveyCHP survey
CHP survey
 
some SHA1 implementation
some SHA1 implementationsome SHA1 implementation
some SHA1 implementation
 
Visulan intro
Visulan introVisulan intro
Visulan intro
 
20151121
2015112120151121
20151121
 
Shizuoka go lang csp
Shizuoka go lang cspShizuoka go lang csp
Shizuoka go lang csp
 
FZ and DAZ in denormals
FZ and DAZ in denormalsFZ and DAZ in denormals
FZ and DAZ in denormals
 
Tech oyaji ksmakoto_presen
Tech oyaji ksmakoto_presenTech oyaji ksmakoto_presen
Tech oyaji ksmakoto_presen
 
Node handson
Node handsonNode handson
Node handson
 
app-c.odp
app-c.odpapp-c.odp
app-c.odp
 

Subprocess no susume

  • 1. subprocessのススメ 岸本 誠 (@ksmakoto)
  • 2. 最近書いているプログラム 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 の間に「いろいろできる」(リダイレクトと か)のを、全部引数で指示するから ● 計算機を仮想化する単位であるプロセスを切り離す 作業だから、仮想化してあるものをここで全部(ファイ ルハンドラとか)面倒を見なきゃならないから
  • 9. ひとつ注意 preexec_fn exec の前に実行される関数引数。なんでも指定できる が、可能な限り余計なことはしてはいけない。英語版ドキュ メントには赤背景で以下のように書いてある。 Warning: The preexec_fn parameter is not safe to use in the presence of threads in your application. The child process could deadlock before exec is called. If you must use it, keep it trivial! Minimize the number of libraries you call into. これは libc に由来するスレッド絡みの制限で、実は厄介。
  • 10. ユースケース ● 標準ライブラリのドキュメントと PEP 324 から ● 以降は from subprocess import * してある 前提で
  • 11. シェルスクリプトのコマンド展開 result=`ls -l myfile` result = check_output([”ls”, ”-l”, ”myfile”])
  • 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 は大 変なことになっている ● ケーススタディをマニュアルから紹介した