當前位置:
首頁 > 知識 > 深入理解子進程

深入理解子進程

sh 的實現

sh 為 Shell 操作提供了一個非常好用的介面,功能也非常強大。

源碼:https://github.com/amoffat/sh/blob/1.12.14/sh.py

代碼總共 3500 多行,這裡只介紹它實現中的關鍵部分,有興趣可以詳細閱讀它的源碼。 讀代碼之前最好先看一下它的文檔 Reference,了解各個對象間的邏輯關係以及代碼執行流程,避免陷入細節中。

從 sh 模塊導入任意命令

我們可以從 sh 模塊導入任意命令,而且這些命令都是動態生成的。

下面解析它的實現:

當導入一個模塊時,Python 的導入機制會創建一個模塊對象存到 中,而 就會獲取該模塊對象的屬性。 把系統創建的模塊對象替換成實現了 方法的模塊對象,就能導入任意命令了。

sh 中相關代碼在 L3333 類 和 L3581 修改 。

優雅的異常處理

sh 支持這樣的用法:

這些異常類都是動態生成的(L433):

它用下面這個正則表達式(L424) 匹配異常類的名稱,取出返回碼或者信號碼:

然後動態生成一個類:

(L325) 是一個元類,動態生成的異常類是元類的實例。

which 命令

sh 用 Python 實現了 命令的功能(L522):

實現原理就是遍歷 環境變數中所有的路徑,找到符合要求的可執行文件:

後面啟動子進程需要用到這個函數。

Command 類的實現

接下來先看 類的實現(L1054),所有命令都是這個類的實例。

它把大量的參數定義放在 中,這樣有幾個好處:

很方便處理大量參數

很方便寫注釋

可讀性更好

因為要允許用戶直接創建 Command 對象,所以又調用了一次 。

接著看它怎麼處理參數的(L1236):

它將參數分成特殊參數(下劃線開頭) 和普通參數,特殊參數能夠控制命令的執行過程, 還能看到它對特殊參數進行了統一校驗,出錯提示也非常清晰。

Command 對象的 方法,功能類似於 :

方法的實現(L1265):

屬性稍後會用到。

Command 是 callable 對象,它的 方法實現比較複雜(L1324):

RunningCommand 是創建子進程執行命令,所以這裡主要是處理參數和三個標準 IO。

處理 管道命令, 如果第一個參數是正在運行的命令,就復用它的標準輸入:

處理 (foreground) 參數:

和 運行的效果差不多,區別在於它不需要通過 sh 進程執行命令。

參數( 參數也差不多):

RunningCommand 的實現

先看介面(L649):

其實和 Popen 的介面差不多,只是它把一堆參數放在 裡面了。

其中有個 參數允許迭代獲取輸出,而不是等子進程結束後再一次性獲取。

通過 創建進程執行命令(L750),之後等待進程結束:

其實 實現了 和 方法, 所以它看上去像字元串,它也實現了 方法,也就能迭代獲取輸出。

OProc 的實現

OProc(L1678) 封裝了創建進程以及進程通信的邏輯,絕大部分特殊參數都是在這處理的。 它的構造函數特別特別長,邏輯太多了。

特殊參數這麼多,估計作者也很無奈:

這裡主要看一下偽終端相關的參數:

Default value: False, meaning a os.pipe() will be used.

Default value: True

If True, sh creates a TTY for STDOUT, otherwise use a os.pipe().

子進程的輸入默認是管道,輸出默認是偽終端。 偽終端是行緩存模式,所以能不停地取到輸出,對比一下前面用 Popen 運行 hello.py 的效果:

sh 把 默認值設為 True 使得它在兼容性方面比 Popen 好很多, Why isttyout=True the default?

大致看一下實現:

後面的 fork, exec 和 Popen 幾乎一樣,就不重複介紹了。

讀後感

sh 的代碼我看了大約一周才理清其中的邏輯,代碼太複雜了。

大致有幾個原因:

Unix 進程本身的複雜性,概念和暗坑很多

用了一些不為人知的 Python 特性(黑魔法)

源碼只有一個文件,3500 代碼,代碼結構不清晰, bottle 項目也是這樣的問題

功能太強大了

源碼中還有非常多細節我沒有提到,其實很多我也不明白,所以只能大致地介紹幾個要點, 梳理一下命令的執行過程,希望能有所幫助 ╮( ̄ ̄")╭

點擊展開全文

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 編程派 的精彩文章:

改善程序員生活質量的 3 10 習慣
一些學習 Python 編程的電子書資源
Python 在騰訊雲的實踐
可視化爬蟲 Portia 試用體驗

TAG:編程派 |

您可能感興趣

深入理解匠人精神
一文深入理解快照技術
交換機埠的深入理解
深入理解手中武器並非易事
馬太效應的深入理解
深度理解景深
深入理解量子混沌可能是實現量子計算機的關鍵
正確理解質子半徑
概念解析:深入理解人工智慧和機器學習
新研究:深入理解憶阻器的工作方式!
愛是深深的理解和接受
深入理解Git的實現原理
愛是深深的理解與接納
要理解深度學習,必須突破常規視角去理解優化
淺入深談:如何更好地理解面向對象編程與面向過程編程的本質區別?
「凝視」海子,去理解那難以理解的生命
深入淺出理解A3C強化學習
深入淺出的理解如何安全的傳輸你的密碼
語文閱讀理解攻略,輕鬆把握句子的意思——細節理解
人體動態理解教程