티스토리 뷰
상황
subprocess.Popen과 subprocess.PIPE를 사용하던 중, 특정 프로세스가 생성된 후 정상적으로 동작하지 않고 좀비 프로세스가 되어 버리는 상황이 발생하였다.
예시 커맨드 및 코드
ls -alh | python test.py | python test2.py
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import subprocess
import traceback
import sys
# ls -alh | python test.py | python test2.py
cmd1 = ['ls', '-alh']
cmd2 = ['python', 'test.py']
cmd3 = ['python', 'test2.py']
try:
ps = subprocess.Popen(cmd1, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
ps2 = subprocess.Popen(cmd2, stdin=ps.stdout, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
res = subprocess.check_output(cmd3, stdin=ps2.stdout, stderr=subprocess.DEVNULL)
except subprocess.CalledProcessError as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
trace_data = ''.join(traceback.format_exception(exc_value))
print(f'{trace_data}')
res = b''
else:
ps.wait()
ps2.wait()
print(res.decode())
|
cs |
- 11 ~ 13 번째 줄: 커맨드 실행
원인 (https://bugs.python.org/issue21619)
프로세스를 연결하는 PIPE 과정에서 IO 버퍼 크기가 작아서 발생하는 문제였다.
Popen 실행 시, bufsize라는 값을 따로 지정하지 않으면 기본 값으로 -1이 들어간다. -1은 공식 문서에 따르면 시스템 기본 값인 io.DEFAULT_BUFFER_SIZE를 사용한다를 의미한다.
그리고 io.DEFAULT_BUFFER_SIZE의 크기는 8192 바이트이다. 공식 bugs.python에서 설명되어 있지만 Popen을 통해 전달되는 데이터가 많아지면 버퍼의 크기가 크지 않아 문제가 발생할 수 있다.
따라서 프로세스에서 버퍼를 통해 파이프라인을 연결할 수 있게 충분한 bufsize를 입력하면 해결된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import subprocess
import traceback
import sys
# ls -alh | python test.py | python test2.py
cmd1 = ['ls', '-alh']
cmd2 = ['python', 'test.py']
cmd3 = ['python', 'test2.py']
MY_BUFSIZE = 2**24
try:
ps = subprocess.Popen(cmd1, bufsize=MY_BUFSIZE, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
ps2 = subprocess.Popen(cmd2, bufsize=MY_BUFSIZE, stdin=ps.stdout, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
res = subprocess.check_output(cmd3, stdin=ps2.stdout, stderr=subprocess.DEVNULL)
except subprocess.CalledProcessError as e:
exc_type, exc_value, exc_traceback = sys.exc_info()
trace_data = ''.join(traceback.format_exception(exc_value))
print(f'{trace_data}')
res = b''
else:
ps.wait()
ps2.wait()
print(res.decode())
|
cs |
참고
'Programming > Python' 카테고리의 다른 글
[socket] select 인자로 class object 사용하는 법 (0) | 2020.10.19 |
---|---|
[unpack] little endian으로 문자열 unpack (0) | 2019.07.08 |
[Mac] import weakref 오류 (0) | 2018.09.14 |
[Python] RAW Socket (0) | 2018.07.18 |
idapython 스크립트 모음 (0) | 2018.06.26 |
댓글