2017-01-26 3 views
3

Hej alle,Kolben: Schreiben direkt an Antwortstream

Ich habe eine Flasche restplus Server anstelle bekam und ich versuche, Excel als Octet-Stream zu meinen Kunden zu erreichen, zu liefern. Es scheint, dass pandas.to_excel (..) beim Serialisieren großer DataFrames viel Zeit verbraucht (30 Sekunden für etwa 120k Zeilen).

Bitte siehe unten meine aktuellen Implementierung:

def format(data_frame): 
    # Idea is to directly write to the flask output stream, instead of buffering 
    # the whole excel as io.BytesIO. Is there a way to do it? 
    output = io.BytesIO() 
    writer = pandas.ExcelWriter(output, engine='xlsxwriter') 
    data_frame_ordered = data_frame.reindex_axis(sorted(data_frame.columns), axis=1) 

    # This consumes a lot of time 
    data_frame_ordered.to_excel(writer, sheet_name='ML Data', na_rep=0, index=False, encoding='utf-8') 

    # This consumes a lot of time, too. 
    writer.save() 

    return output.getvalue() 


@api.route('/excel', methods=['GET']) 
class ExcelResource(Resource): 
    def get(self, args): 
     # Well, thats a huge pandas.DataFrame 
     data_frame = ... 
     resp = make_response(format(data_frame)) 
     resp.headers['Content-Length'] = resp.content_length 
     resp.headers['Content-Type'] = 'application/octet-stream' 

     return resp 

Gibt es eine Möglichkeit, die Excel direkt in den Kolben Ausgabestrom zu schreiben, ohne es in eine BytesIO Instanz Pufferung?

Vielen Dank im Voraus

Dennis

Antwort

1

Sie können versuchen, eine Datei-ähnliches Objekt zu erstellen, die Ihnen zur Verfügung gestellten Streaming-Schnittstelle, wie:

import threading 
from flask import Response 
from Queue import Queue 


class StreamWriter(object): 
    def __init__(self): 
     self.queue = Queue() 

    def write(self, some): 
     self.queue.put(some) 

    def read(self): 
     return self.queue.get(True) 

    def flush(self): 
     pass 

    def tell(self): 
     #probably some code 
     pass 

    def seek(self): 
     #probably some code 
     pass 

    def close(self): 
     self.queue.put(None) 

@api.route('/excel', methods=['GET']) 
class ExcelResource(Resource): 
    def get(self, args): 
     def generate(): 
      output = StreamWriter() 

      def do_stuff(): 
       output = StreamWriter() 

       writer = pandas.ExcelWriter(output, engine='xlsxwriter') 
       data_frame_ordered = data_frame.reindex_axis(sorted(data_frame.columns), axis=1) 

       # This consumes a lot of time 
       data_frame_ordered.to_excel(writer, sheet_name='ML Data', na_rep=0, index=False, encoding='utf-8') 

       # This consumes a lot of time, too. 
       writer.save() 
       output.close() 

      threading.Thread(target=do_stuff).start() 
      while True: 
       chunk = output.read() 
       if chunk is None: 
        break 
       yield chunk 

     return Response(generate(), headers={some_headers}) 

Es ist nur eine grobe Idee, und dieser Code ist nicht getestet!