深入理解子進程
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強化學習
※深入淺出的理解如何安全的傳輸你的密碼
※語文閱讀理解攻略,輕鬆把握句子的意思——細節理解
※人體動態理解教程