<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我們日常測試中存在大量重複的造數操作,且流程較長,為了提升測試效率,我們搭建了資料構造平臺。平臺採用了前端 + 指令碼分離的形式,資料構造指令碼獨立存在,頁面和指令碼的關聯關係通過頁面設定進行繫結。
頁面設定中,包含了指令碼的路徑以及啟動命令,因此,執行指令碼的時候需要在伺服器上啟動子程序中去執行指令碼命令。為了能夠了解指令碼的執行情況,還需要獲取指令碼的執行狀態以及執行紀錄檔。
平臺後端語言是 Python,因此,選擇了 Python 中的 subprocess 模組,本文重點闡述 subprocess 模組在專案實戰中遇到的問題以及解決方案。
本文涉及的程式執行環境如下:
Python 版本:3.8.3
作業系統:windows server
subprocess 模組允許我們啟動一個新程序,並連線到它們的輸入/輸出/錯誤管道,從而獲取返回值。subprocess 模組首先推薦使用的是它的 run 方法,更高階的用法可以直接使用 Popen 介面。
subprocess.run() 方法是 3.5 版本新增的,用於可以接受等待程序執行結束後獲取返回值的場景,如果可以滿足使用需求,官方推薦使用 run() 方法。
subprocess.run() 的執行過程是同步的,指令碼執行結束之前是阻塞的,只有指令碼結束之後才會返回 subprocess.CompletedProcess 物件。
subprocess.Popen() 是 subprocess 的核心,子程序的建立和管理都靠它處理。Popen() 相當於 run() 的高階版本,更加靈活,使開發人員能夠處理 run() 方法未涵蓋的更豐富的場景。subprocess.Popen() 是非同步的,程序啟動以後,我們可以通過預先指定好的 stdout 和 stderr 來實時讀取到子程序的輸出。
subprocess.Popen()常用引數介紹:
args:shell命令,可以是字串或者序列型別(如:list,元組)
stdin, stdout, stderr:分別表示程式的標準輸入、輸出、錯誤控制程式碼
shell:如果該引數為 True,將通過作業系統的 shell 執行指定的命令,args只能是String型別的引數;該引數為False,args可以是序列型別。
Popen 物件常用方法:
poll(): 檢查程序是否終止,如果終止返回 returncode,否則返回 None,專案中通過該方法返回判斷程序是否執行結束。
wait(timeout): 等待子程序終止,如果程序執行時間較長,可以使用該方法來保證程序執行完整。
communicate(input,timeout): 和子程序互動,傳送和讀取資料。
send_signal(singnal): 傳送訊號到子程序 。
terminate(): 停止子程序,也就是傳送SIGTERM訊號到子程序。
kill(): 殺死子程序。傳送 SIGKILL 訊號到子程序。
Run() 和 Popen() 同步/非同步的簡單對比如下:
從執行結果可以看出,Popen 在子程序執行過程中就可以獲取到紀錄檔,run 需要等待程序執行完成才能獲取到紀錄檔。如果需要執行的命令耗時很短,可以選擇 run 方法。因為我們的資料構造流程通常比較長,需要實時獲取紀錄檔,所以選擇了 Popen。
在使用 Popen 的過程中也遇到了一些問題,下面將具體介紹一下遇到的問題以及解決方案。
subprocess.Popen() 可以獲取到執行過程中的紀錄檔了,那我們如何保證程序紀錄檔獲取的完整性呢?我們來看下具體方案:
方案一:這是我們最開始採用的方案。通過獲取方法 poll() 返回的狀態碼來檢查程序是否終止。如果終止,返回 returncode,否則返回 None,程式碼如下:
該方案在使用的過程中存在問題。當子程式已經執行完畢,紀錄檔還沒有獲取完整,會出現紀錄檔接收不全的情況。為了解決這種問題,保證紀錄檔的完整性,我們選擇通過判斷紀錄檔是否讀取完畢作為判斷依據,詳細參見方案二。
方案二:通過判斷紀錄檔是否讀取完畢保證紀錄檔完整性。程式碼如下:
這種方法看似解決了紀錄檔不全的問題,但是存在著一定的風險。紀錄檔為 None 無法有效保證子程序執行結束(雖然經過多方實踐,暫時沒有發現紀錄檔為 None 但指令碼未執行結束的情況)。為了安全起見,我們還是需要兼顧一下程序的執行狀態,具體參見方案三。
方案三:通過判斷 poll() 返回狀態和紀錄檔返回值,也就是說,程式狀態結束且返回物件為空,才表示子程序已經執行結束,並且獲取到了完整的紀錄檔,程式碼如下:
該方案已經比較完善了,通過子程序執行結束並且執行紀錄檔為 None,保證執行紀錄檔的完整性。美中不足的是,紀錄檔資訊可能會比實際的多一些,當輸出先讀取完畢,子程序還沒有結束,我們會獲取到一部分空行,為了紀錄檔的美觀度,我們可以進一步優化,獲取紀錄檔的時候,過濾掉空行,程式碼如下:
通過判斷輸出流和程序的執行狀態,完美的解決了上面的問題,保證了紀錄檔的完整性與正確性。
如何保證指令碼程序正常終止 當指令碼執行以後,我們可能會因為某些原因想終止指令碼的執行,如引數錯誤等。 在我們專案程式碼中,使用 Popen.terminate() 去終止程序的時候,發現命令只終止了父程序,喚起的子程序仍然在執行。
為了找到原因,先看一下專案中建立 Popen 的程式碼:
引數介紹的時候提到過,shell 為 True 或 False 時,command 的型別是有要求的。因為我們 command 傳值是 String 型別,引數 shell 只能設定為 True。當 shell=True 的時,程式會建立一個 shell 程序,command 是 shell 程序的子程序。
我們再來看下 Popen.terminate() 做了什麼?官方的說明如下:
Stop the child. On POSIX OSs the method sends SIGTERM to the child. On Windows the Win32 API function TerminateProcess()is called to stop the child
也就是說,在 POSIX 系統中,該方法會傳送 SIGTERM 訊號給子程序;
在 Windows 系統中,該方法會呼叫 Win32 提供的 API TerminateProcess() 方法。
原因很清晰了,當 shell=True 的時候,傳送 SIGTERM 能夠殺死 shell 程序,但是無法殺死它的子程序(command);windows 系統中同理,TerminateProcess() 殺死了 shell 程序,卻沒有殺死它的子程序(command)。
方案一:比較優雅的方式,建立 Popen 物件時,將引數 shell 設為 False。實踐發現,當 shell=False 的時候,Popen.terminate() 方法的執行結果是符合預期的;
subprocess.Popen(command, shell=False)
前面提到過,因為 command 格式問題,在我們專案中,shell 只能設定為 True,所以我們又探索了新的解決方案。
方案二:手動終止程序。使用第三方工具包 psutil,獲取全部的子程序並逐一殺掉,該方法在 Linux 和 windows 平臺通用。程式碼見下圖。
在 windows 伺服器下,還可以用以下命令:
taskkill /t /f /pid {pid},強制殺掉指定程序以及它的子程序。
windows 平臺的方案無需第三方依賴,所以我們專案中選擇了該方案,專案程式碼如下:
以上就是 Python 中的 subprocess 模組在我們專案實踐中遇到的問題以及解決方案,希望可以給大家提供一些使用思路以及規避掉一系列問題,更多關於Python測試開發subprocess的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45