IT/python

[python] Popen 을 통해 dict 주고 받기

심량 2020. 8. 12. 20:11

Popen 을 사용해서 하위 프로세스를 생성하는 구조인데 단순 데이터만 주고 받는 것을 상정하다가 사전 구조인 dictionary 데이터를 주고 받으려니 삽질을 길게 하게 되네요..

from subprocess import Popen, PIPE
import json
...(중략)...
for proc in self.list:
    proc = Popen(['python3', proc.name], stdin=PIPE, stdout=PIPE)
...(중략)...
for proc in self.list:
    proc.stdin.write('hi kids\r\n'.encode())
    proc.stdin.flush()

원래는 이런 구조였습니다. 하지만 write 하는 곳에서 dict 형태의 데이터를 넘겨야 할 필요가 생겼을 때 문제가 생겼습니다..

자식쪽에서는 stdin 이나 stdout 을 readline() 함수로 읽고 있는데 이 함수 때문에 반드시 부모가 write 할 때 '\r\n' 이 포함되야 하고 자식도 그것을 그대로 받습니다.

이걸 빼먹으면 readline() 에 걸리지 않습니다.

그리고 dict 를 write 하게 했더니 Broken PIPE 가 뜨기도 하고 read 가 되기는 하는데 받는 쪽에서 dict 로 환원을 못하기도 하더군요..

마지막에는 

인터넷을 엄청 뒤져서 이것 저것 적용해보다가 지쳐갈 무렵 결국 을 찾았네요

json.dumps(data) 호출하면 "key": "value" 형태로 인용부호가 출력됩니다. json.loads 가 정상적으로 data를 처리하려면 dumps 가 생성한 형태로 되어 있어야 합니다. 하나의 프로세스에서 처리하면 정상적으로 동작합니다. 하지만 이 내용을 PIPE를 통해 다른 프로세스로 전달하면 \'key\': \'value\' 와 같은 형태로 변형되어 있습니다. json.loads(data) 를 호출하면 거의 대부분 잘 읽어오는 것처럼 보이지만 맨 끝 } 가 안 닫히고 뭔가 데이터가 불안정해 보입니다.

이 데이터를 PIPE 로 받은 직후 \'를 모두 \" 로 변경하면 json.loads(data) 결과가 깨끗하게 보입니다.


# main 프로세스 쪽
import json, sys

dict_data = { 'hi': 'hello', 'hum':17 }             # 원본 dict 데이터
dict_data['temp'] = int(time.time())% 10            # 걍 임시 데이터 'temp' 추가
bin_data = json.dumps(dict_data)                    # bytes 로 직렬화 변환
# readline 때문에 개행문자 추가 후 다시 bytes 로 변환
pipe_data = f'{bin_data}\r\n'.encode('utf-8')
sys.stdin.write(final_data)                         # 파이프에 데이터 쓰기
sys.stdin.flush()                                   # 대기 버퍼 강제 실행

# sub 프로세스 쪽
import json, sys
msg = sys.stdin.readline()
if msg:
	dict_data = json.loads(msg[:-2].strip("'<>() ").replace('\'', '\"'))
	pipe_data = f'{dict_data}\r\n'
	sys.stdout.write(pipe_data)
	sys.stdout.flush()