天天看點

【python】協程

關于python協程這個知識點,我是在研究locust時候發現的。

locust是一款開源的性能測試工具,單機并發能力要比jmeter高,它的并發實作就是通過python協程去實作的。

說到并發,我猜你很容易想到的是多線程,其實協程也是實作并發的一種方式,隻不過協程是單線程。

先上一段代碼,假設我們在寫爬蟲抓取4個url的内容,并且我們讓每一個url都停留一定的秒數,第一個1s,

第二個停2s,以此類推。是以,可以知道4個url爬取完畢一共要花費10s的時間。

運作一下:

果然運作了10s,可以發現我們在等待中浪費了很多時間,那麼如何提高這段代碼的運作效率呢?

沒錯,協程該出場了。

目前,python3.7以上的版本提供了最新的寫法,是基于<code>asyncio</code> 和 <code>async / await</code> 的方法,是以如果下面

的代碼你執行不起來,檢查一下是不是你的python版本不對。

async:聲明這是一個異步函數。調用異步函數,就會得到一個協程對象。

await:用于調用函數。注意,這裡await 執行的效果,和 python 正常執行是一樣的。

也就是說程式會阻塞在這裡,進入被調用的協程函數,執行完畢傳回後再繼續。

asyncio.run:觸發運作。這個函數是 python 3.7 之後才有的特性,目的就是讓python 的協程接口變得非常簡單。

通常情況下,<code>asyncio.run(main())</code> 作為主程式的入口函數,在程式運作周期内,隻調用一次 <code>asyncio.run</code>。

上述代碼其實還沒完成,不信你執行一下,會發現還是10s。這正如上面await介紹說的,其實跟python正常執行一次沒差別。

是以,為了實作協程,還需要<code>asyncio.create_task</code>來建立任務。

執行一下:

這下僅需要4s,也就是4個任務中,耗時最長的那個任務所需要的時間。

執行過程:

在第一個for循環裡,通過調用異步函數<code>crawl_page()</code>得到4個協程對象。

在第二個for循環裡,通過<code>asyncio.create_task</code>給4個協程對象分别建立了task。

接着,4個任務被<code>await</code>調用執行。

是不是很簡單?再次印證了python哲學:簡單勝過複雜。

最近可能會用到locust對項目進行性能測試,若有收獲,屆時分享。