파이썬 subprocess

업데이트:

스크립트를 파이썬으로 작성하면 가독성과 유지보수성을 향상시킬 수 있다. 또한 파이썬으로 시작한 자식 프로세스를 병렬로 실행할 수 있어서 CPU를 많이 사용하는 작업을 관리하고 조절하기 쉽다. 반면 파이썬 프로세스 자체는 병렬처리가 까다롭다.

Subprocess

subprocess 내장 모듈을 통해 자식 프로세스를 쉽게 관리할 수 있다.

Poen생성자는 프로세스를 생성한다. communicate메서드는 자식 프로세스의 출력을 읽어오고 종료할 때까지 기다린다.

proc = subprocess.Popen(
	['echo', 'Hello from the child!'],
  stdout=subprocess.PIPE)
out, err = proc.commmunicate()
print(out,decode('utf-8'))

# Hello from the child!

자식 프로세스는 부모 프로세스와 파이썬 인터프리터와는 독립적으로 실행된다. 자식 프로세스의 상태는 파이썬이 다른 작업을 하는 동안 주기적으로 polling 된다.

proc = subprocess.Popen(['sleep', '0.3'])
while proc.poll() is None:
  print('Working...')
  # 시간이 걸리는 작업을 수행
print('Exit Status', proc.poll())

# Working...
# Working...
# Exit Status 0

Pipe를 이용해 데이터를 subprocess로 보낸 다음 subprocess의 결과를 받아올 수 있다. 또한 받아온 결과를 다른 프로세스의 입력으로 연결하여 병렬 프로세스 체인을 생성할 수도 있다.

def run_openssl(data):
  env = os.environ.copy()
  env['password'] = b'password'
  proc = subprocess.Popen(
  	['openssl', 'enc', '-des3', '-pass', 'env:password'],
  	env=env,
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE)
  proc.stdin.write(data)
  proc.stdin.flush() # 자식 프로세스가 반드시 입력을 받게끔 함
  return proc
  
def run_md5(input_stdin):
  proc = subprocess.Popen(
  	['md5'],
  	stdin=input_stdin,
  	stdout=subprocess.PIPE)
 	return proc
  
  
# openssl로 데이터를 암호화하는 프로세스 집합 결과를
# md5로 해시하는 프로세스 집합에 연결한다.
input_procs = []
hash_procs = []

for _ in range(3):
  data = os.urandom(10)
  proc = run_openssl(data)
  input_procs.append(proc)
  hash_proc = run_md5(proc.stdout)
  hash_procs.append(hash_proc)
  
for proc in input_procs:
  proc.communicate()
for proc in hash_procs:
  out, err = proc.communicate()
  print(out.strip())
  # b'7a1207387120391.....'

자식 프로세스가 deadlock에 빠지거나 입력 또는 출력 파이프에서 블록될 염려가 있다면 communication 메서드에 timeout파라미터를 넘겨야 한다.

proc = subprocess.Popen(['sleep', str(10)])
try:
  proc.communicate(timeout=0.1)
except subprocess.TimeoutExpired:
  proc.terminate()
  proc.wait()

print('Exit status', proc.poll()) # Exit Status -15

Reference

파이썬 코딩의 기술. 브렛 슬라킨

댓글남기기