2016-01-28 13 views
10

tl; dr Un metodo decorato con route non può gestire richieste simultanee mentre Flask viene servito dietro una gunicorn avviata con più worker e thread, mentre due metodi diversi gestiscono le richieste simultanee. Perché è così, e in che modo la stessa rotta può essere servita contemporaneamente?Come ottenere Flask/Gunicorn per gestire richieste simultanee per lo stesso percorso?


ho questa semplice applicazione pallone: ​​

from flask import Flask, jsonify 
import time 
app = Flask(__name__) 

@app.route('/foo') 
def foo(): 
    time.sleep(5) 
    return jsonify({'success': True}), 200 

@app.route('/bar') 
def bar(): 
    time.sleep(5) 
    return jsonify({'success': False}), 200 

Se corro questa via:

gunicorn test:app -w 1 --threads 1 

Se apro rapidamente /bar e /foo in due diverse schede in un browser, la scheda che premo invio per prima verrà caricata in 5 secondi e la seconda scheda verrà caricata in 10 secondi. Questo ha senso perché gunicorn esegue un lavoratore con un thread.

Se corro questa tramite uno:

gunicorn test:app -w 1 --threads 2 
gunicorn test:app -w 2 --threads 1 

In questo caso, l'apertura e /foo/bar in due diverse schede prendono entrambi 5 secondi. Questo ha senso, perché gunicorn esegue sia 1 worker con due thread, o due worker con un thread ciascuno, e può servire le due rotte allo stesso tempo.

Tuttavia, se apro due /foo allo stesso tempo, indipendentemente dalla configurazione di gunicorn, la seconda scheda richiederà sempre 10 secondi.

Come è possibile ottenere lo stesso metodo decorato da route per soddisfare richieste simultanee?

risposta

9

Questo problema probabilmente non è causato da Gunicorn o Flask ma dal browser. Ho appena provato a riprodurlo. Con due schede di Firefox funziona; ma se eseguo due processi curl in diverse console, vengono forniti come previsto (in parallelo) e le loro richieste vengono gestite da diversi operatori: è possibile verificarlo abilitando --log-level DEBUG all'avvio di gunicorn.

Penso che questo sia dovuto al fatto che Firefox (e forse altri browser) aprono una singola connessione al server per ogni URL; e quando apri una pagina su due schede, le loro richieste vengono inviate attraverso la stessa connessione (mantenuta viva) e come risultato arrivano allo stesso operatore.

Di conseguenza, anche utilizzando lavoratore asincrono come eventlet non aiuterà: operaio asincrono può gestire più connessioni alla volta, ma quando due richieste atterrano sulla stessa connessione allora saranno necessariamente essere gestita one-by-one .

+1

Interessante che originariamente il comportamento di tale browser riguardo alle connessioni è inteso a * accelerare * il caricamento evitando il sovraccarico extra di stabilire nuove connessioni. Ma in questa situazione (con una gestione lenta dal lato server) vediamo che può rallentare le cose. – MarSoft

+0

Ho appena provato con una scheda in Chrome e una scheda in Firefox e ho ricevuto i risultati previsti. Grazie e bella chiamata. –

Problemi correlati