2013-06-18 9 views
7

desidero streaming blocchi di dati da un generatore nel pallone dopo ho chiamato la funzione con jQuery $ .post():

@app.route('/some/function', methods=['POST']) 
def calculateSomething(): 
    def g():   
     # do something here 
     yield 'result1' 
     # do more ...     
     yield 'result2'  
    return Response(g()) 

io chiamo questa funzione da jQuery:

$.post("/some/function", {"some": $data}, function(data) { 
    alert(result) 
}) 

questo mi dà solo un avviso dicendo 'result1result2' e non due avvisi separati per ogni resa. Quindi la funzione di callback viene chiamata dopo che tutto è stato "restituito".

Come posso inviare correttamente stream a jQuery con rendimento?

risposta

3

Questa è una richiesta AJAX e si gestisce alert quando tutti i dati verranno caricati. non è possibile ottenere pezzi separati, perché è una richiesta, ma può provare emulare questo:

  1. Si può provare utilizzare XMLHttpRequest2.progress event, ProgressEvent.loaded e leggere i dati da XMLHttpRequest2.response, ma quando questo evento sarà gestito davvero difficile domanda (in particolare per ciascun browser).

  2. Puoi anche provare a guardare WebRTC ma questo ci sono limitazioni con il supporto dei browser e sembra irragionevolmente difficile per il tuo caso.

  3. Non dimenticare di flash e così via, ma sembra anche irragionevolmente difficile per il tuo caso.

Se la vostra risposta rapida quindi è possibile ottenere tutte le risposte e dati separati sul client (ad esempio è possibile utilizzare JSON con base64 per gli oggetti binari o blob se si conosce la struttura blob).

Se la tua risposta è lunga perché ottieni grandi quantità di dati e hai davvero bisogno di pezzi, è meglio fare diverse richieste perché il tempo per la nuova connessione sarà inferiore al grosso chunk di caricamento. In questo caso, meglio non utilizzare grandi blocchi per AJAX perché possono generare eccezioni timeout.

Se la vostra risposta è lunga perché richiede molta CPU o operazioni lente, è meglio iniziare il processo in background (come celery), restituire la risposta e dopo aver verificato i risultati con un certo intervallo.

Se è necessario ottenere una risposta estremamente veloce, provare a utilizzare web sockets (in questo caso è necessario inviare messaggi diversi).

Così, quando in streaming e pezzi saranno utili:

  1. È download o upload file di grandi dimensioni e si desidera il controllo della velocità in applicazione pallone (le citazioni degli utenti, non utilizzare tutti i canali per questa operazione). Tuttavia, se si utilizza ad esempio uwsgi, il processo o il thread verranno bloccati durante l'elaborazione di questa operazione.
  2. Si sta scaricando o caricando un file di grandi dimensioni e si desidera interrompere/ripristinare/verificare questa operazione.
+0

Immagino che la strada da percorrere sia spostare processi in esecuzione prolungata in background, salvare tutto in rosso e lasciare che il client si aggiorni continuamente. Prese Web o qualcosa di simile sono eccessivo :) –

6

In questo caso è possibile utilizzare eventi inviati dal server.Controlla il seguente esempio:

from flask import Flask, Response 
import time 

app = Flask(__name__) 

@app.route('/') 
def index(): 
    return """ 
<!DOCTYPE html> 
<html> 
    <head> 
    <script> 
     if(typeof(EventSource)!=="undefined") { 
     var source=new EventSource("/stream"); 
     source.onmessage=function(event) { 
      document.getElementById("result").innerHTML+=event.data + "<br>"; 
     }; 
     } else { 
     document.getElementById("result").innerHTML="Sorry, your browser does not support server-sent events..."; 
     } 
    </script> 
    </head> 
    <body> 
    <h1>Data</h1> 
    <div id="result"></div> 
    </body> 
</html> 
""" 

@app.route('/stream', methods=['GET', 'POST']) 
def stream(): 
    def event_stream(): 
     n = 0 
     while True: 
      yield "data: %s\n\n" % n 
      n += 1 
      time.sleep(1) 
    return Response(event_stream(), mimetype='text/event-stream') 

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

Gli eventi di server inviati bloccano il server di sviluppo. Per gestire più connessioni, guarda a Gevent. http://flask.pocoo.org/docs/deploying/others/#gevent