ASGI解釋:Python Web開發的未來
譯文?譯者 | 李睿
審校 | 孫淑娟
Python Web應用程序長期以來一直遵循Web服務器網關接口(WSGI)標準,該標準描述了它們如何與Web服務器通信。WSGI最初于2003年推出,并于2010年更新,僅依賴于Python2.2版本中原生可用的、易于實現的功能。因此, WSGI迅速融入了所有主要的Python Web框架,并成為Python Web開發的基石。
快進到2022年。Python2已經過時,Python現在具有處理網絡調用等異步操作的原生語法。WSGI和其他默認假定同步行為的標準無法利用異步的性能和效率增益。這反過來又意味著WSGI不能有效地處理像WebSocket這樣的高級協議。
輸入ASGI,即異步服務器網關接口。與WSGI類似,ASGI描述了Python Web應用程序和Web服務器之間的通用接口。與WSGI不同的是,ASGI允許每個應用程序有多個異步事件。另外,ASGI支持同步和異步應用程序。開發人員可以將原有的同步WSGI Web應用程序遷移到ASGI,也可以使用ASGI構建新的異步Web應用程序。
1.WSGI的工作原理
WSGI的工作原理是向Web服務器公開Python函數,通常命名為應用程序或app。該函數采用兩個參數:
- environ:包含有關當前請求和Web服務器提供的環境變量的信息的字典。
- start_response:將用于啟動將HTTP響應發送回客戶端的函數。
函數返回的數據構成響應體。
一個簡單的應用程序函數可能如下所示:?
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
return [b'Greetings universe']
如果使用的是與WSGI兼容的Web框架(例如Flask),那么該框架本身將提供一個應用程序功能,其所有組件將自動連接。
WSGI有兩個缺點:首先,WSGI一次只處理一個請求和響應,并假設響應將立即返回。沒有辦法處理長時間保持的連接,例如WebSocket或長輪詢HTTP連接。
其次,WSGI只是同步的。即使使用多線程連接池,每個連接都會阻塞,直到它返回響應。許多WSGI設置都能夠處理線程池和進程池,但這些都受到WSGI接口本身同步的限制。
2.ASGI的工作原理?
ASGI在外觀上與WSGI相似。與WSGI一樣,開發人員可以定義一個應用程序函數對象,但它是一個帶有三個參數而不是兩個參數的異步函數:
scope:包含有關當前請求的信息的字典,類似于WSGI中的environ,但細節的命名約定略有不同。
send:允許應用程序將消息發送回客戶端的異步可調用函數。
receive:允許應用程序從客戶端接收消息的異步可調用函數。
一個簡單的ASGI應用程序函數如下所示:
async def application(scope, receive, send):
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'text/plain'],
],
})
await send({
'type': 'http.response.body',
'body': b'Hello, world!',
})
與WSGI Web框架一樣,ASGI Web框架將生成自己的application()函數,并根據需要將其連接起來。
與ASGI最明顯的區別是,在整個函數中使用了異步隱喻。該函數本身是異步的,在此通過兩個單獨的await send( )命令發送HTTP標頭和響應正文。這樣,函數本身及其發送命令就不會阻塞任何內容;它們可以與應用程序的調用交織在一起,并可以同時從許多其他連接發送。
在這個例子中沒有使用receive,但它也是一個異步函數。它讓在不阻塞其他操作的情況下接收請求正文。請求和響應可以以這種方式增量地傳入或傳出服務器——這是無法很好地完成的事情,或者可能根本無法使用WSGI完成的。
3.在ASGI中使用同步和異步函數?
使用ASGI時,需要盡可能多地使用異步函數和異步友好庫。養成使用異步的習慣是值得的,因為使用僅同步代碼的問題可能很嚴重。任何對同步函數的長時間調用都會阻塞整個調用鏈,從而使使用異步的好處幾乎消失殆盡。
如果在使用長時間運行的同步調用時遇到問題,需要使用asyncio.run_in_executor將調用外包給線程池或進程池。每當等待外部事件或非CPU密集型任務時,都應使用線程池。而進程池應該用于CPU密集型的本地任務。
例如,Web應用程序中有一個路由可以調用遠程網站,那么應該使用線程。或者更好的方法是,使用發出異步HTTP請求的aiohttp庫。如果想調用Pillow圖像庫來調整圖像大小,可能應該使用帶有進程池的run_in_executor。盡管在進程之間來回傳輸數據會有一些輕微的開銷,但使用run_in_executor不會阻塞其他事件。
4.支持ASGI的Web框架
通過實現application( )對象,可以人工編寫ASGI Web應用程序。但絕大多數情況下,使用異步原生、以ASGI為中心的Python Web框架會更簡單。以下是一些常見的與ASGI兼容的Web框架:
Starlette和FastAPI:這些新興框架(FastAPI構建在Starlette之上)都是異步優先的,因此它們都支持ASGI也就不足為奇了。如果是從零開始開發Web應用程序,那么它們是Python最現代和最前沿的Web框架。
Quart:雖然主要的Python Web框架Flask確實支持ASGI,但Flask的設計并不是從內到外利用異步隱喻。來自GitLab的Quart使用Flask的語法和隱喻,但允許異步路由處理程序。
Django 3.0及更高版本:從Django3.0開始,久負盛名的Django Web框架支持ASGI。在Django 3.1中添加了對Django應用程序中異步代碼的支持,而不是僅僅能夠在ASGI處理程序上掛載Django。對于一個不以執行速度著稱的框架來說,異步的存在為那些選擇利用它的人帶來了更好的性能。
原文鏈接:https://www.infoworld.com/article/3658336/asgi-explained-the-future-of-python-Web-development.html?