2016-01-11 16 views
8

我嘗試設置一個最小的Flask應用程序,它使用eventlet立即響應併發請求,而不是阻塞另一個請求並響應另一請求(如標準Flask調試Web服務器所做的那樣)。使用Flask和eventlet響應併發請求

先決條件:

pip install Flask 
pip install eventlet 

從我迄今發現在互聯網上我的理解,它應該像這樣工作:

# activate eventlet 
import eventlet 
eventlet.monkey_patch() 

from flask import Flask 

import datetime 
from time import sleep 

# create a new Flask application 
app = Flask(__name__) 

# a short running task that returns immediately 
@app.route('/shortTask') 
def short_running_task(): 
    start = datetime.datetime.now() 
    return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now()) 

# a long running tasks that returns after 30s 
@app.route('/longTask') 
def long_running_task(): 
    start = datetime.datetime.now() 
    sleep(30) 
    return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now()) 

# run the webserver 
if __name__ == '__main__': 
    app.run(debug=True) 

當運行這個文件,然後在網頁瀏覽器打開http://localhost:5000/longTask標籤,雖然它仍在處理打開另一個標籤http://localhost:5000/shortTask,但我期望第二個標籤在第一個標籤仍在加載時立即返回。但是,與在標準Werkzeug服務器上運行此類似的情況類似,第二個選項卡僅在第一個標籤在30秒之後完成後才返回。

這裏有什麼問題? 順便說一下,鑑於只有很少的併發用戶(最多5個),這是否會被稱爲Flask的「生產就緒webserver」?

順便說一下,當我使用the Flask-socketio library來運行網絡服務器時,根據文檔,如果它安裝時會自動選擇eventlet,那麼它將按預期工作。

與燒瓶socketio完整的示例:

# activate eventlet 
import eventlet 
eventlet.monkey_patch() 

from flask import Flask 
from flask_socketio import SocketIO 

import datetime 
from time import sleep 

# create a new Flask application 
app = Flask(__name__) 

# activate Flask-socketio 
socketio = SocketIO(app) 

# a short running task that returns immediately 
@app.route('/shortTask') 
def short_running_task(): 
    start = datetime.datetime.now() 
    return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now()) 

# a long running tasks that returns after 30s 
@app.route('/longTask') 
def long_running_task(): 
    start = datetime.datetime.now() 
    sleep(30) 
    return 'Started at {0}, returned at {1}'.format(start, datetime.datetime.now()) 

# run the webserver with socketio 
if __name__ == '__main__': 
    socketio.run(app, debug=True) 

回答

11

當您運行app.run(debug=True)時,您明確告訴Flask在基於Werkzeug的開發Web服務器上運行您的應用程序。加載eventlet無關緊要。

如果你想運行的eventlet Web服務器上的應用程序,你必須開始一個eventlet Web服務器,它根據the documentation啓動如下:

wsgi.server(eventlet.listen(('', 8000)), your_app) 

這是多了還是少了什麼socketio.run()呢在我的Flask-SocketIO擴展中,稍微複雜一些,可以選擇處理SSL。這樣做的代碼行是:https://github.com/miguelgrinberg/Flask-SocketIO/blob/539cd158f49ce085151911cb63edbacd0fa37173/flask_socketio/init.py#L391-L408。如果你仔細看看這些行,你會看到有三個不同的代碼塊,一個用於werkzeug,一個用於eventlet,另一個用於gevent。他們都是不同的。

+0

優秀!必須將Flask應用程序對象傳遞給'wsgi.server'命令在我看來並不清楚,因爲這個基於Flask的示例非常有用。 – Dirk

2
import eventlet 
eventlet.monkey_patch() 

不會奇蹟般地把你的代碼放到一個多線程的野獸可以異步處理請求(這仍然是相當神奇,真棒)。

正如您在this example中看到的,您需要使用eventlet wsgi's implementation啓動wsgi服務器。

如果你想要一個標準的解決方案,看看如何使用nginx和uwsgi來啓動燒瓶應用程序。您也可能對項目Spawning感興趣,它們利用創建完整的多線程wsgi處理程序的痛苦。