首頁 > 軟體

http通過StreamingHttpResponse完成連續的資料傳輸長連結方式

2022-02-12 16:00:27

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的過程中,所以這有可能會降低伺服器的效能。

參考檔案

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com