2017-08-10 28 views
1

我有一個有2個端點的API,一個是接收JSON的簡單文章,另一個是根據jsons列表長度多次調用第一個端點並將返回保存到列表的端點。如何在python中多線程調用另一個端點方法?

第一種方法

@app.route('/getAudience', methods=['POST', 'OPTIONS']) 
def get_audience(audience_=None): 
    try: 
     if audience_: 
      audience = audience_ 
     else: 
      audience = request.get_json() 
    except (BadRequest, ValueError): 
     return make_response(jsonify(exception_response), 500) 

    return get_audience_response(audience, exception_response) 

方法二

@app.route('/getMultipleAudience', methods=['POST', 'OPTIONS']) 
def get_multiple_audience(): 
    try: 
     audiences = request.json 
    except (BadRequest, ValueError): 
     return make_response(jsonify(exception_response), 500) 

    response = [] 
    for audience in audiences: 
     new_resp = json.loads(get_audience(audience).data) 
     response.append(new_resp) 

    return make_response(jsonify(response)) 

我想叫第一種方法在第二種方法的啓動列表中每個對象的線程,所以我嘗試這樣做:

def get_multiple_audience(): 
    with app.app_context(): 
     try: 
      audiences = request.get_json() 
     except (BadRequest, ValueError): 
      return make_response(jsonify(exception_response), 500) 

     for audience in audiences: 
      thread = Thread(target=get_audience, args=audience) 
      thread.start() 

     thread.join() 
     return make_response(jsonify(response)) 

並得到這個錯誤:

Exception in thread Thread-6: 
Traceback (most recent call last): 
    File "C:\Python27\lib\threading.py", line 801, in __bootstrap_inner 
    self.run() 
    File "C:\Python27\lib\threading.py", line 754, in run 
    self.__target(*self.__args, **self.__kwargs) 
    File "C:\Python27\lib\site-packages\flask_cors\decorator.py", line 123, in wrapped_function 
    options = get_cors_options(current_app, _options) 
    File "C:\Python27\lib\site-packages\flask_cors\core.py", line 286, in get_cors_options 
    options.update(get_app_kwarg_dict(appInstance)) 
    File "C:\Python27\lib\site-packages\flask_cors\core.py", line 299, in get_app_kwarg_dict 
    app_config = getattr(app, 'config', {}) 
    File "C:\Python27\lib\site-packages\werkzeug\local.py", line 347, in __getattr__ 
    return getattr(self._get_current_object(), name) 
    File "C:\Python27\lib\site-packages\werkzeug\local.py", line 306, in _get_current_object 
    return self.__local() 
    File "C:\Python27\lib\site-packages\flask\globals.py", line 51, in _find_app 
    raise RuntimeError(_app_ctx_err_msg) 
RuntimeError: Working outside of application context. 

於是我試圖修改這樣的第一種方法:

@app.route('/getAudience', methods=['POST', 'OPTIONS']) 
def get_audience(audience_=None): 
    with app.app_context(): 
     try: 
     ... 

,並得到了同樣的錯誤。任何人都可以給我一個提示,建議,最佳實踐或解決方案嗎?

+0

如果要測試您的Web服務,最好的方法是使用請求創建單獨/獨立的應用程序。 –

+0

@LaurentLAPORTE這不是他們所問的 – davidism

回答

1

這裏有很多問題。首先,在這裏:

for audience in audiences: 
    thread = Thread(target=get_audience, args=audience) 
    thread.start() 

thread.join() 

您只是在等待最後一個線程完成。你應該有一個所有的線程列表,並且等待全部其中的完成。

threads = [] 
for audience in audiences: 
    thread = Thread(target=get_audience, args=audience) 
    threads.append(thread) 
    thread.start() 

for thread in threads: 
    thread.join() 

第二個問題是,你正在返回一個response它甚至沒有設置任何地方。但這不是多線程的工作原理。你將有來自所有線程的多個結果,你將不得不跟蹤它們。所以你可以創建一個results數組來保存每個線程返回值的答案。在這裏我將以一個簡單的函數sum爲例。

results = [] 
threads = [] 

def sum(a, b): 
    results.append(a + b) 

@app.route("/test") 
def test(): 
    with app.app_context(): 
     for i in range(5): 
      t = Thread(target=sum, args=(1, 2)) 
      threads.append(t) 
      t.start() 

     for t in threads: 
      t.join() 

     return jsonify(results) 

這將愉快地工作,並且將返回所有呼叫的結果sum()功能。

現在,如果我改變總和:

@app.route("/mysum/a/b") 
def sum(a, b): 
    results.append(a + b) 
    return jsonify(a + b) 

我會得到一個類似的錯誤,你前面都拿到了一個,即:RuntimeError: Working outside of request context.,甚至認爲返回值仍然是正確的:[3, 3, 3, 3, 3]。這裏發生的是,sum函數現在試圖返回瓶響應,但它駐留在它自己的臨時線程中,並且無法訪問任何瓶的內部上下文。你應該做的是永遠不要return臨時工作者線程內的值,但有一個池來存儲它們以備將來參考。

但這並不意味着你不能有/mysum路線。的確,你可以,但邏輯必須分開。把它放在一起:

results = [] 
threads = [] 

def sum(a, b): 
    return a + b 

def sum_worker(a, b): 
    results.append(sum(a, b)) 

@app.route("/mysum/a/b") 
def mysum(a, b): 
    return jsonify(sum(a, b)) 

@app.route("/test") 
def test(): 
    with app.app_context(): 
     for i in range(5): 
      t = Thread(target=sum_worker, args=(1, 2)) 
      threads.append(t) 
      t.start() 

     for t in threads: 
      t.join() 

     return jsonify(results) 

請注意,這段代碼是非常粗糙的,僅用於演示目的。我不建議在整個應用程序中創建全局變量,因此需要進行一些清理。

相關問題