2017-07-28 41 views
4

我目前正在創建一個使用Python燒瓶的web應用程序,我碰到了一個路障,我不確定我是否正確地考慮它。Python燒瓶返回一個html頁面,同時執行一個功能

因此,我的網站的主頁只是一個簡單的登陸頁面,需要執行網站功能的文本輸入。我試圖完成的是讓web應用程序在文本輸入後執行兩件事。首先,服務器接受用戶名輸入並執行一個函數,該函數不會向用戶返回任何內容,但會創建一堆登錄到sqlite數據庫的數據,並在稍後的過程中使用。然後,服務器返回用戶名輸入後必須進行調查的網頁。但是,根據用戶的不同,服務器執行的功能可能需要2分鐘。我現在編碼的方式是服務器執行該功能,然後一旦完成,它將返回網頁,因此用戶被困在加載屏幕上最多2分鐘。

@app.route("/survey") 
def main(raw_user): 
    raw_user = request.args.get("SteamID")  < 
    games = createGameDict(user_obj)   <----- the function 
    tag_lst = get_tags(games)     < 
    return render_template("survey_page.html") 

由於調查不依賴於用戶的輸入,而不是讓用戶坐在載入畫面,我希望他們能夠開始調查,而功能在後臺工作,是那可能,我該怎麼做?

+2

我會用'celery'來進行異步任務管理。 http://flask.pocoo.org/docs/0.12/patterns/celery/ –

+0

Celery的一個不太乾淨的替代方法是爲該方法提供一個路徑(在@ decorator中),並在調查頁面調用ajax請求時調用它被加載。 –

回答

3

對於更復雜的背景任務,像芹菜是最好的選擇。但對於更簡單的用例,您需要的是threading模塊。

請看下面的例子:

from flask import Flask 
from time import sleep 

app = Flask(__name__) 


def slow_function(some_object): 
    sleep(5) 
    print(some_object) 

@app.route('/') 
def index(): 
    some_object = 'This is a test' 
    slow_function(some_object) 
    return 'hello' 

if __name__ == '__main__': 
    app.run() 

在這裏,我們創建了一個功能,slow_function()在返回前睡五秒鐘。當我們在路由功能中調用它時,它會阻止頁面加載。運行該示例,然後在瀏覽器中點擊http://127.0.0.1:5000,然後在加載之前,您會看到頁面等待五秒鐘,然後在終端中打印測試消息。

我們想要做的是將slow_function()置於不同的線程。隨着只是一對夫婦的代碼其它行,我們可以使用threading模塊給這個函數的執行分離出在不同的線程:

from flask import Flask 
from time import sleep 
from threading import Thread 

app = Flask(__name__) 


def slow_function(some_object): 
    sleep(5) 
    print(some_object) 

@app.route('/') 
def index(): 
    some_object = 'This is a test' 
    thr = Thread(target=slow_function, args=[some_object]) 
    thr.start() 
    return 'hello' 

if __name__ == '__main__': 
    app.run() 

我們在這裏所做的很簡單。我們正在創建一個Thread的新實例,並將它傳遞給兩件事:target(這是我們想要運行的函數)和args(即要傳遞給目標函數的參數)。請注意,slow_function上沒有括號,因爲我們不是,它運行的是它 - 函數是對象,所以我們將函數本身傳遞給Thread。至於args,這總是期待一個列表。即使你只有一個參數,將其包裝在一個列表中,以便args得到它所期望的。

隨着我們的線程準備就緒,thr.start()執行它。在你的瀏覽器中運行這個例子,你會注意到索引路由現在立即加載。但再等五秒鐘,果然,測試信息將打印在您的終端中。

現在,我們可以在這裏停下來 - 但至少在我看來,實際上在線路本身內部存在這個線程代碼有點麻煩。如果你需要在另一條路線或不同的環境中調用這個函數呢?最好把它分成它自己的功能。你可以將線程行爲本身作爲慢函數的一部分,或者你可以創建一個「包裝器」函數 - 你採取的方法很大程度上取決於你在做什麼以及你的需求。

讓我們創建一個包裝函數,看看它是什麼樣子:

from flask import Flask 
from time import sleep 
from threading import Thread 

app = Flask(__name__) 


def slow_function(some_object): 
    sleep(5) 
    print(some_object) 

def async_slow_function(some_object): 
    thr = Thread(target=slow_function, args=[some_object]) 
    thr.start() 
    return thr 

@app.route('/') 
def index(): 
    some_object = 'This is a test' 
    async_slow_function(some_object) 
    return 'hello' 

if __name__ == '__main__': 
    app.run() 

async_slow_function()功能做得非常正是我們所做的事情 - 它只是有點整潔了。你可以在任何路徑上調用它,而不必重新重寫你的線程邏輯。你會注意到這個函數實際上返回了線程 - 我們不需要需要對於這個例子,但是以後可能還想用其他的方法來處理這個線程,所以如果你使用線程對象需要它。

相關問題