Python 非同步呼叫命令列工具

Yusheng發表於2016-11-21

當你在自己的 Python 程式中採用了基於事件迴圈的非同步程式設計方法之後,你就會發現自己不自覺地被其牢牢吸引住,並不是說這一方法多麼棒,而是因為你不得不想辦法保證程式中的任意環節都不能是阻塞的!

例如當前的場景是希望從 MongoDB 中讀取每一條未處理過的資料,下載並儲存其中的圖片資訊,然後更新資料庫的內容。Python 常用的 MongoDB 非同步驅動是 Motor:

Python 非同步呼叫命令列工具

結合 asyncio 使用方法如下:

此時如果 dl_img() 處的操作是阻塞的,那麼非同步處理就沒有意義了。當然這裡依然可以藉助非同步網路請求庫 aiohttp 來實現圖片下載:

當然也可以不需要自己動手下載,直接呼叫系統命令列工具(例如 wget)來完成下載任務。Python 通過 subprocess 標準庫實現系統命令呼叫(取代舊的os.system(cmd)),執行下載任務只需要:

但是這種呼叫方式是無法直接在asyncio的事件迴圈中使用的,但是asyncio提供了對應的 subprocess介面

這兩個方法均返回一個 asyncio.subprocess.Process 例項,而它的介面設計完全模仿了 subprocess.Popen(上面提到 subprocess.run()的底層實現),因此很容易將其用法移植到事件迴圈中:

除了上面場景中的用法,也可以直接將命令列的執行作為任務放入事件迴圈:

小結

在 Python 非同步程式設計的意義就在於不要讓 CPU 堵在 IO 上,因此需要在每一處涉及到阻塞的操作都需要注意使用正確的非同步方法,而一旦這些操作被封裝成非同步的 Task 之後,其後續的排程執行就無需再顧慮了。

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

Python 非同步呼叫命令列工具

相關文章