python基礎教程:異步IO 之 概念和歷史

編程中,咱們常常會遇到「併發」這個概念,目的是讓軟件能充分利用硬件資源,提升性能。併發的方式有多種,多線程,多進程,異步IO等。多線程和多進程更多應用於CPU密集型的場景,好比科學計算的時間都耗費在CPU上,利用多核CPU來分擔計算任務。多線程和多進程之間的場景切換和通信代價很高,不適合IO密集型的場景(關於多線程和多進程的特色已經超出本文討論的範疇,有興趣的同窗能夠自行搜索深刻理解)。而異步IO就是很是適合IO密集型的場景,好比網絡爬蟲和Web服務。python

在計算機程序中,IO就是讀寫磁盤、讀寫網絡的操做,這種讀寫速度比讀寫內存、CPU緩存慢得多,前者的耗時是後者的成千上萬倍甚至更多。這就致使,IO密集型的場景99%以上的時間都花費在IO等待的時間上。異步IO就是把CPU從漫長的等待中解放出來的方法。這就能夠大大提升咱們寫的軟件系統的併發性。這樣的軟件,能夠是網絡爬蟲,也能夠是Web服務等一切IO密集型的系統。程序員

異步IO的優點顯而易見,各類語言都經過實現這個機制來提升自身的效率,Python也不例外。Python經歷了2和3兩個大版本的躍遷。這其中也有對異步IO支持的變化歷程。golang

Python 2的異步IO庫

Python 2 時代官方並無異步IO的支持,可是有幾個第三方庫經過事件或事件循環(Event Loop)實現了異步IO,它們是:web

  • twisted: 是事件驅動的網絡庫
  • gevent: greenlet + libevent(後來是libev或libuv)。經過協程(greenlet)和事件循環庫(libev,libuv)實現的gevent使用很普遍。
  • tornado: 支持異步IO的web框架。本身實現了IOLOOP。

Python 3 官方的異步IO

Python 3.4 加入了asyncio 庫,使得Python有了支持異步IO的官方庫。這個庫,底層是事件循環(EventLoop),上層是協程和任務。asyncio自從3.4 版本加入到最新的 3.7版一直在改進中。django

Python 3.4 剛開始的asyncio的協程仍是基於生成器的,經過 yield from 語法實現,能夠經過裝飾器 @asyncio.coroutine (已過期)裝飾一個函數來定義一個協程。好比:編程

Python 3.5 引入了兩個新的關鍵字 await 和 async 用來替換 @asyncio.coroutine 和 yield from ,從語言自己來支持異步IO。從而使得異步編程更加簡潔,並和普通的生成器區別開來。緩存

注意: 對基於生成器的協程的支持已棄用,並計劃在 Python 3.10 中移除。因此,寫異步IO程序時只需使用 async 和 await 便可。網絡

Python 3.7 又進行了優化,把API分組爲高層級API和低層級API。 咱們先看看下面的代碼,發現與上面的有什麼不一樣?多線程

除了用 async 替換 @asyncio.coroutine 和用 await 替換 yield from 外,最大的變化就是關於eventloop的代碼不見了,只有一個 async.run()。這就是 3.7 的改進,把eventloop相關的API納入到低層級API,新引進run()做爲高層級API讓寫應用程序的開發者調用,而不用再關心eventloop。除非你要寫異步庫(好比MySQL異步庫)纔會和eventloop打交道。併發

須要注意的是, async.run() 是3.7版新增長的,處於暫定API狀態。 暫定API,是指被有意排除在標準庫的向後兼容性保證以外的應用編程接口。雖然此類接口一般不會再有重大改變,但只要其被標記爲暫定,就可能在覈心開發者肯定有必要的狀況下進行向後不兼容的更改(甚至包括移除該接口)。此種更改並不會隨意進行 — 僅在 API 被加入以前未考慮到的嚴重基礎性缺陷被發現時纔可能會這樣作。即使是對暫定 API 來講,向後不兼容的更改也會被視爲「最後的解決方案」 —— 任何問題被確認時都會盡量先嚐試找到一種向後兼容的解決方案。這種處理過程容許標準庫持續不斷地演進,不至於被有問題的長期性設計缺陷所困。

從上面關於 asyncio 的發展來看它一直在變化,3.4,3.5,3.6, 3.7 都有不少細節上的變化。當我看到3.7的run()函數時,也發現一年前基於3.6的asnycio寫的爬蟲不那麼優雅了。

這種變化,一方面改善了asyncio自己的性能和使用方便程度,但另外一方面也增長了咱們使用者的學習成本、Python升級帶來的改造的成本。若是你以消極的態度抵制這種變化,能夠去學習golang,C++來實現你的程序;若是你以積極的態度迎接這種變化,能夠更快的掌握這種變化,並優雅 高效的實現你的程序。

只要你喜歡用Python寫程序解決問題,那麼就接受並掌握這種變化吧。其實,那種語言不在變,那種技術不在前進。做爲程序員,你只有不斷地學習和前進。

uvloop

uvloop是用Cython寫的,基於libuv這個C語言實現的高性能異步I/O庫。asyncio本身的事件循環是用Python寫的,用uvloop替換asyncio本身的事件循環能夠是asyncio的速度更快。而且使用至關簡潔:

你們在學python的時候確定會遇到不少難題,以及對於新技術的追求,這裏推薦一下咱們的Python學習扣qun:784758214,這裏是python學習者彙集地!!同時,本身是一名高級python開發工程師,從基礎的python腳本到web開發、爬蟲、django、數據挖掘等,零基礎到項目實戰的資料都有整理。送給每一位python的小夥伴!每日分享一些學習的方法和須要注意的小細節

相關文章
相關標籤/搜索