天天看點

uvloop —— 超級快的 Python 異步網絡架構

uvloop —— 超級快的 Python 異步網絡架構

簡短介紹

asyncio是遵循python标準庫的一個異步 i/o架構.在這篇文章裡,我将介紹 uvloop: 可以完整替代asyncio事件循環.uvloop是用cython寫的,基于 libuv.

uvloop 使得 asyncio 更快. 實際上,比nodejs,gevent,以及其他任何python異步架構至少快兩倍 .uvloop asyncio 基于性能的測試接近于go程式.

asyncio 和 uvloop

asyncio 子產品, 是在 pep 3156引入的, 是一個集合,包含網絡傳輸, 協定, 和抽象的流, 帶有可插拔的事件循環. 事件循環是asyncio的核心.它提供如下api:

調用方法的排程

通過網絡傳輸資料

執行 dns 查詢,

處理 os 作業系統信号

對建立伺服器和連接配接進行封裝

子程序異步處理

目前 uvloop 隻支援 *nix 平台和 python 3.5。

uvloop 是 python 内建的 asyncio 事件循環的替代品,你可以通過 pip 來安裝:

$ pip install uvloop 

在你的 asyncio 代碼中使用 uvloop 非常簡單:

import asyncio 

import uvloop 

asyncio.set_event_loop_policy(uvloop.eventlooppolicy()) 

上面的代碼片段讓 asyncio.get_event_loop() 傳回一個 uvloop 的執行個體。

你還可以顯式的建立一個uvloop執行個體,通過調用uvloop.new_event_loop()。

體系結構

uvloop是用cython編寫的,并建立在libuv之上。

libuv是一種高性能的、跨平台異步的 i/o 類庫,nodejs也使用到了它。由于nodejs是如此的廣泛和流行,可以知道libuv是快速且穩定的。

uvloop 實作了所有的asyncio 事件循環apis。進階别的python對象包裝了低級别的libuv 結構體和函數方法。 繼承可以使得代碼保持dry(不要重複自己),并確定任何手動的記憶體管理都可以與libuv的原生類型的生命周期保持同步。

基準測試

與其它實作相比,為了檢測uvloop棧性能,我們建立了toolbench基準測試,用于标準的tcp和unix套接字i/o,和http協定性能的基準 。

基準測試伺服器運作在一個包含外部負載生成工具 (wrk http 基準測試)的docker容器内,它測試請求吞吐量與延遲。

這篇部落格中所有的基準測試都運作于intel xeon cpu e5-1620 v2 @ 3.70ghz的 ubuntu linux系統.我們使用的是python 3.5,所有伺服器都是單核. 此外,go代碼中使用了gomaxprocs=1 ,nodejs沒有使用叢集,并且所有的python伺服器都是單線程.每一個基準測試集都設定了tcp_nodelay辨別。

在mac os x上的基準報告結果也很相似。

tcp

這個基準測試使用不同的消息數目對一個簡單的回顯伺服器的性能進行了測試。我們分别使用了1, 10, 和100 kib 的包。并發級别是10。每一個基準運作了30秒。

可以點選這裡檢視完整的tcp基準報告。

uvloop —— 超級快的 Python 異步網絡架構

每個位置的一些意見:

asyncio-streams。 asyncio 和其内置的純python實作的事件循環。在這個基準測試中,我們測試了進階别的流的抽象的性能。我們使用asyncio.create_server()來建立一個伺服器,把一對(reader, writer) 傳遞給用戶端協同程式.

tornado。 這個伺服器實作了一個非常簡單的tornado 協定,它能夠把收到的消息立即回複回去。

curio-streams。 curio是python aio 庫上的新成員。 與asyncio-streams類似,在這個基準測試中,我們測試了curio 流,使用curio.make_streams()來建立了一對(reader, writer),它提供了一些進階的api,如readline()。

twisted。 跟tornado類似,我們測試了一個最小的回聲協定。

curio。這個基準測試測試了curio 套接字的性能:這是一個實作了sock.recv() 和 sock.sendall()緊密循環的協同程式。

uvloop-streams。就如在#2中提到的,這裡我們測試了asyncio進階流的性能,隻不過這此時基于uvloop。

gevent。在一個緊密循環裡通過使用gevent.streamserver和一個gevent套接字發送接受資料。

asyncio。看起來普通的asyncio非常的快速!跟第2和4點類似,我們測試了一個最小的回聲協定,它是使用純python的asyncio所實作的。

nodejs。我們使用net.createserver api 在nodejs v4.2.6裡測試流的性能。

uvloop。這個基準測試測試了一個最小的回聲協定(就如 #2, #4, #8),它是使用基于uvloop的asyncio實作的。 使用1 kib消息的情況下,uvloop是最快的實作,可以高達每秒鐘105,000的請求!使用100 kib消息的情況下, uvloop的速度可以達到大概2.3 gib/s。

go。一個 net.conn.read/write 調用的緊密循環。 golang 性能跟uvloop非常接近,在10 和100 kib消息情況下會稍微好一些。

所有的基準測試的代碼可以在這裡找到。

也可以檢視所有的unix套接字基準測試結果。

http

最初,我們想要在asyncio和uvloop上針對nodejs和go進行測試。aiohttp是使用asyncio編寫異步http伺服器和用戶端 最流行的架構。

也可以檢視完整的http基準測試報告。

然而,aiohttp 上的性能瓶頸确實其http解析器,它比較慢,是以即使使用的i/o類庫再快也沒什麼卵用。為了讓事情更有趣,我們為 http-parser (nodejs的 http 解析器c類庫,最初是為nginx研發的) 建立了一個python綁定(binding)。這個類庫被命名為httptools,并且在github和pypi都可以找到。

對于http,所有的基準使用wrk 來生成負載。 并發級别設定為300。每個基準的持續時間為30秒。

uvloop —— 超級快的 Python 異步網絡架構

令人驚奇的是,純python實作的asyncio在高性能的http解析器的幫助下,比使用同樣http解析器的nodejs表現的快很多!

go在1 kib響應情況下要更快些,但是uvloop和asyncio的組合卻在10/100 kib響應情況下要快很多。使用httptools的asyncio和uvloop的服務品質非常棒,對于go來說也一樣。

不可否認,基于httptools的伺服器非常的小巧,而且不像其他實作那樣不包含任何路由邏輯。盡管如此,這個基準卻示範了uvloop和一個高效實作的協定配合能變得多麼快速。

conclusion

我們可以得出結論, 利用uvloop可以寫出在單cpu核心下每秒鐘能夠發出上萬個請求的python網絡代碼。 在多核心系統下,可以使用程序池來進一步來改善系統性能。

uvloop 和 asyncio,在加上python 3.5裡 async/await的強大能力,使得使用python編寫高性能的網絡代碼更容易了。

本文作者:佚名

來源:51cto