http通過StreamingHttpResponse完成連續的數據傳輸長鏈接方式
http通過StreamingHttpResponse完成連續的數據傳輸長鏈接
問題
http服務之間傳遞結果流
一個由flask封裝起來的算法,一個由django封裝的後臺,我希望在django裡通過requests調用flask的算法接口,flask可以分析一幀返回一幀結果,追求分析結果的實時返回,而不是完全分析完再完整返回結果
為瞭能完整返回結果,暫時想到的模式有以下三種:
- 一問一答:等待完整的分析結果,然後返回,最不濟就用這種
- 我要你給(長鏈接):flask返回一個generator,django取next就得到下一個的結果
- 你有你給(理想,長鏈接):建立長鏈接,flask每分析出一幀結果,就返回
一次結果,直到分析結束,關閉連接
看到flask中有個flask_socketio建立socket連接,還沒有實驗
暫時用StreamingHttpResponse,generater能實現實時分析的感覺,屬於第三種模式(你有你給)
django的StreamingHttpResponse可以返回generater,request調用返回generate的接口的時候,通過contextlib 的closing對流進行處理:
輸出
#django 算法端,輸出流 from django.http import StreamingHttpResponse def stream_response(request): def generate(): for i in range(10): print(i) yield 'hi ' + str(i) print('sleep 3') time.sleep(1) return StreamingHttpResponse(generate(), )
#flask 算法端,輸出流 @app.route('/re', methods=('POST', )) def re(): @flask.stream_with_context def generate(): for i in range(10): print(i) yield 'hi ' + str(i) print('sleep 3') time.sleep(1) return flask.Response(generate())
輸入
不區分flask,django,都可以通過request,contextlib 實現
#flask 算法端 @app.route('/test', methods=['POST', 'GET']) def test(): url = 'http://172.16.68.151:8000/test2' from contextlib import closing with closing(requests.get(url, stream=True)) as r1: for i in r1.iter_content(): print(i)
StreamingHttpResponse和HttpResponse
在修改以前的文件下載功能時,發現一個文件有5G,用HttpResponse實現時,服務器返回502錯誤,查看nginx log時,發現nginx log記錄的是: upstream prematurely closed connection while reading response header from upstream。應該是nginx服務器從上遊獲取數據時超時瞭。
查瞭很多辦法,修改瞭nginx的配置,但是仍然超時。
絕望之下,查瞭一下Django的文檔,發現瞭StreamingHttpResponse,試瞭一下效率提高瞭很多。
後來仔細查瞭一下發現HttpResponse在使用文件迭代器時:
HttpResponse will consume the iterator immediately, store its content as a string, and discard it.
HttpResponse會直接使用迭代器對象,將迭代器對象的內容存儲城字符串,然後返回給客戶端,同時釋放內存。可以當文件變大看出這是一個非常耗費時間和內存的過程。
而StreamingHttpResponse是將文件內容進行流式傳輸,
StreamingHttpResponse在官方文檔的解釋是:
The StreamingHttpResponse class is used to stream a response from Django to the browser. You might want to do this if generating the response takes too long or uses too much memory.
這是一種非常省時省內存的方法。但是因為StreamingHttpResponse的文件傳輸過程持續在整個response的過程中,所以這有可能會降低服務器的性能。
參考文檔
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 詳解Django關於StreamingHttpResponse與FileResponse文件下載的最優方法
- Python Django搭建文件下載服務器的實現
- Django框架HttpResponse和HttpRequest對象學習
- Python3+Flask安裝使用教程詳解
- Django 狀態保持搭配與存儲的實現