파이썬에서 subprocess 를 활용해 자식 프로세스를 실행하면서,
자식 프로세스의 입출력 스트림을 관리 및 활용할 수 있습니다
import subprocess
result = subprocess.run(['echo', 'Hello from subprocess!'], capture_output=True, text=True)
print(result.stdout)
# Hello from subprocess!
위 코드를 통해 subprocess에 터미널 명령을 넣어주면 아래와 같은 결과값을 얻을 수 있음을 확인할 수 있습니다.
만약 내가 터미널 명령을 통한 결과값을 이용해 파이프라인을 구축하고 싶다면
Popen 클래스를 활용해 유닉스 스타일의 파이프라인을 구축해볼 수 있을 것 같은데요.
여기서 유닉스 스타일의 파이프라인이란 유닉스 계열 운영체제에서 제공하는 파이프라인( | ) 를 사용해서
여러 명령어 출력 및 입력을 연결하는 방식을 말합니다
import subprocess
# 'echo'의 출력을 'grep'의 입력으로 전달하는 파이프라인 예제
with subprocess.Popen(['echo', 'Hello from subprocess!'], stdout=subprocess.PIPE) as proc1:
with subprocess.Popen(['grep', 'Hello'], stdin=proc1.stdout, stdout=subprocess.PIPE) as proc2:
output = proc2.communicate()[0]
print(output.decode('utf-8'))
# Hello from subprocess!
위와 같이 파이프라인으로 표현된 명령어를 표현할 수 있을 것 입니다.
다른 예제로 확인해보면,
cat somefile.txt | grep "some pattern" | sort
위 명령어를 아래와 같은 방식으로 표현이 가능할 것 입니다.
import subprocess
# 첫 번째 명령어: cat somefile.txt
with subprocess.Popen(['cat', 'somefile.txt'], stdout=subprocess.PIPE) as proc1:
# 두 번째 명령어: grep "some pattern"
with subprocess.Popen(['grep', 'some pattern'], stdin=proc1.stdout, stdout=subprocess.PIPE) as proc2:
# 세 번째 명령어: sort
with subprocess.Popen(['sort'], stdin=proc2.stdout, stdout=subprocess.PIPE) as proc3:
output = proc3.communicate()[0]
print(output.decode('utf-8'))
만일, subprocess의 예상된 실행시간을 초과해버리면 어떻게 할까요?
그땐 commuicate의 파라미터 timeout를 활용해 실행결과 시간을 제한해
시간이 지나버리면 오류가 발생할 수 있게 유도할 수 있습니다.
import subprocess
with subprocess.Popen(['sleep', '10'], stdout=subprocess.PIPE) as proc:
try:
output = proc.communicate(timeout=5)[0]
except subprocess.TimeoutExpired:
proc.kill()
output = proc.communicate()[0]
print("Process timed out!")
마지막으로, subprocess가 병렬로 실행되고 있다는 것을 확인해볼 수 있는 코드를 보면서
이런 병렬성을 어떻게 활용할 수 있는지 까지 알아볼 수 있을 것 같습니다
import subprocess
import time
def run_command_in_parallel(commands):
"""여러 명령어를 병렬로 실행하고 결과를 반환합니다."""
processes = []
for cmd in commands:
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
processes.append(proc)
results = []
for proc in processes:
stdout, stderr = proc.communicate()
results.append((stdout, stderr))
return results
def main():
# 예제: 동시에 여러 'sleep' 명령어 실행
commands = [
['sleep', '5'],
['sleep', '5'],
['sleep', '5']
]
start_time = time.time()
run_command_in_parallel(commands)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"Total time taken: {elapsed_time:.2f} seconds")
if __name__ == "__main__":
main()
# Total time taken: 5.01 seconds
마지막에 5초라는 시간이 결과값으로 나온 것을 확인함으로써 병렬로 실행되고 있음을 알 수 있습니다.
이러한 병렬이라는 특색을 이용해 아래와 같은 시스템을 구축하거나 활용해볼 수 있을 것 같습니다.
- 데이터 처리: 큰 데이터 세트를 여러 부분으로 나누고, 각 부분을 독립적으로 처리한 후 결과를 합치는 작업에 사용될 수 있습니다. 예를 들어, 로그 파일을 분석하거나 대규모 텍스트 데이터를 처리할 때 유용합니다.
- 병렬 컴파일: 큰 소프트웨어 프로젝트에서 여러 소스 파일을 동시에 컴파일하여 전체 빌드 시간을 단축시킬 수 있습니다.
- 시뮬레이션 및 모델링: 과학적 연구나 엔지니어링에서 복잡한 시뮬레이션을 여러 파라미터로 동시에 실행하여 결과를 빠르게 얻을 수 있습니다.
- 웹 크롤링: 여러 웹사이트나 페이지를 동시에 크롤링하여 데이터를 수집하는 데 사용될 수 있습니다.
- 배치 작업: 여러 작업을 동시에 실행하여 시스템의 처리 용량을 최대한 활용할 수 있습니다. 예를 들어, 여러 이미지나 동영상 파일을 동시에 변환하는 작업 등이 있습니다.
- 테스트 자동화: 여러 테스트 케이스나 시나리오를 동시에 실행하여 소프트웨어의 테스트 시간을 단축시킬 수 있습니다.
- 분산 시스템: 여러 노드나 서버에서 동시에 작업을 실행하여 분산 시스템의 성능을 테스트하거나 최적화할 수 있습니다.
'프로그래밍 언어 > Python' 카테고리의 다른 글
컨텍스트 스위칭으로부터의 예상치 못한 결과 ( feat.GIL ) (0) | 2023.09.20 |
---|---|
Thread와 Queue를 활용한 파이프라인 구현하기( feat. 콘웨이 생명게임 ) (0) | 2023.09.19 |
GIL를 무조건 신뢰하면 안되는 이유( feat.스레드 감수성 ) (0) | 2023.09.15 |
두 코드의 차이점을 설명하시요( feat. Python,쓰레드, GIL, 병렬 I/O) (0) | 2023.09.15 |
클래스를 디버깅해보자(feat.메타클래스,클래스 데코레이터) (0) | 2023.09.15 |