![](/img/trans.png)
[英]How to return stdout from long running process with subprocess and Popen?
[英]How to return a dictionary as a function's return value running as a subprocess to its parent process?
我有兩個腳本 parent.py 和 child.py parent.py 調用 child.py 作為子進程。 Child.py 有一個函數可以在字典中收集某些結果,我希望將該字典返回給父進程。 我曾嘗試將該字典從 child.py 打印到其 STDOUT 上,以便父進程可以讀取它,但這對我沒有幫助,因為字典的內容被父進程讀取為單獨行上的字符串。
此外,正如評論中所建議的,我嘗試使用 JSON 序列化字典,同時在標准輸出上打印它,並使用 JSON 從父級讀取它,這工作正常,但我也將許多其他信息從子級打印到其標准輸出最終也被父母閱讀並且正在混淆。
提出的另一個建議是將子進程的結果寫入目錄中的文件,並使父進程從該文件中讀取。 這也可以,但是我會在 Celery 中運行 100 個此代碼的實例,因此它會導致其他子實例覆蓋同一文件。
我的問題是,由於我們有一個連接這兩個進程的 PIPE,我如何才能將我的字典直接從 child.py 寫入 PIPE 並從 parent.py 中讀取它
# parent.py
import subprocess
proc = subprocess.Popen(['python3', 'child.py'],
stdin=subprocess.PIPE,
stdout = subprocess.PIPE
)
proc.comunicate()
result = proc.stdout
#child.py
def child_function():
result = {}
result[1] = "one"
result[2] = "two"
print(result)
#return result
if __name__ == "__main__":
child_function()
運行 Python 的子進程與運行其他東西的子進程沒有任何區別。 Python 不知道或不關心其他程序是否也是 Python 程序; 他們無法訪問彼此的變量、內存、運行狀態或其他內部信息。 簡單地想象一下子進程是一個整體的二進制文件。 您可以與之通信的唯一方法是發送和接收字節(可以是字符串,如果您同意字符編碼)和信號(這樣您就可以終止子進程,或引發其他一些可以捕獲和處理的信號 - - 就像一個計時器;當計時器到期時,您只會獲得一位信息,而您對該位的處理取決於信號的接收者)。
“序列化”信息意味着以允許接收者反序列化的方式對其進行編碼。 JSON 就是一個很好的例子; 您可以將包含(可能是嵌套結構)字典或列表的結構作為文本傳輸,並且接收者將知道如何將該字節流映射到相同的結構中。
當發送方和接收方運行相同的 Python 版本時,您也可以使用泡菜; pickle 是一種原生 Python 格式,它允許您傳輸更豐富的結構。 但如果您的需求不大,我會簡單地使用 JSON。
parent.py
:
import subprocess
import json
# Prefer subprocess.run() over bare-bones Popen()
proc = subprocess.run(['python3', 'child.py'],
check=True, capture_output=True, text=True)
result = json.loads(proc.stdout)
child.py
:
import json
import logging
def child_function():
result = {}
result[1] = "one"
result[2] = "two"
loggging.info('Some unrelated output which should not go into the JSON')
print(json.dumps(result))
#return result
if __name__ == "__main__":
logging.basicConfig(level=logging.WARNING)
child_function()
為避免將 JSON 與其他輸出混合,請將其他輸出打印到標准錯誤而不是標准輸出(或者畢竟想辦法將其嵌入到 JSON 中)。 logging
模塊是一種方便的方法,您可以輕松地、部分地或完全地將其關閉(上面的示例演示了通過logging.basicConfig
關閉的日志記錄,因為它只選擇打印優先級為WARNING
的消息)或更高,不包括INFO
)。 父proc.stderr
將在proc.stderr
獲取這些消息。
讓父級為子級創建一個 FIFO(命名管道):
with os.mkfifo(mypipe) as pipe:
proc = subprocess.Popen(['python3', 'child.py', 'mypipe'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
print(pipe.read())
現在孩子可以這樣做:
pipe_path = # get from argv
with open(pipe_path, 'w') as pipe:
pipe.write(str(result))
這使您的通信與 stdin/stdout/stderr 分開。
您可以通過文件獲取結果。
父母.py:
import tempfile
import os
import subprocess
import json
fd, temp_file_name = tempfile.mkstemp() # create temporary file
os.close(fd) # close the file
proc = subprocess.Popen(['python3', 'child.py', temp_file_name]) # pass file_name
proc.communicate()
with open(temp_file_name) as fp:
result = json.load(fp) # get dictionary from here
os.unlink(temp_file_name) # no longer need this file
孩子.py:
import sys
import json
def child_function(temp_file_name):
result = {}
result[1] = "one"
result[2] = "two"
with open(temp_file_name, 'w') as fp:
json.dump(result, fp)
if __name__ == "__main__":
child_function(sys.argv[1]) # pass the file name argument
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.