/ / Jak poprawić wydajność Pythona, który odczytuje duży plik i zwraca go jako plik do pobrania? - python, cgi, performance, mod-wsgi

Jak poprawić wydajność python cgi, który czyta duży plik i zwraca go jako pobieranie? - python, cgi, performance, mod-wsgi

Mam ten skrypt python cgi, który sprawdza, czy nie uzyskano do niego dostępu wiele razy z tego samego adresu IP, a jeśli wszystko jest w porządku, odczytuje duży plik z dysku (11 MB), a następnie zwraca go jako plik do pobrania.

Działa, ale wydajność jest do kitu. Wąskim gardłem wydaje się ciągłe czytanie tego ogromnego pliku:

def download_demo():
"""
Returns the demo file
"""

file = open(FILENAME, "r")
buff = file.read()

print "Content-Type:application/x-downloadnContent-Disposition:attachment;filename=%snContent-Length:%snn%s" %    (os.path.split(FILENAME)[-1], len(buff), buff)

Jak mogę to zrobić szybciej? Myślałem o użyciu dysku RAM, aby zachować plik, ale musi być jakieś lepsze rozwiązanie. Użyłbym mod_wsgi zamiast pomocy skryptu cgi? Czy byłbym w stanie zatrzymać duży plik w pamięci Apache?

Każda pomoc jest bardzo doceniana.

Odpowiedzi:

9 dla odpowiedzi № 1

Użyj mod_wsgi i użyj czegoś podobnego do:

def application(environ, start_response):
status = "200 OK"
output = "Hello World!"

response_headers = [("Content-type", "text/plain")]
start_response(status, response_headers)

file = open("/usr/share/dict/words", "rb")
return environ["wsgi.file_wrapper"](file)

Innymi słowy, użyj wsgi.file_wrapper rozszerzenie standardu WSGI, aby umożliwić Apache / mod_wsgi wykonanie zoptymalizowanej odpowiedzi na zawartość pliku przy użyciu sendfile / mmap. Innymi słowy, unika twojej aplikacji nawet konieczności odczytu pliku do pamięci.


2 dla odpowiedzi nr 2

Dlaczego drukujesz w jednym wydrukukomunikat? Python musi wygenerować kilka tymczasowych ciągów znaków do obsługi nagłówków treści, a ze względu na ostatnie% s musi przechowywać całą zawartość pliku w dwóch różnych zmiennych ciągach. Tak powinno być lepiej.

print "Content-Type:application/x-downloadnContent-Disposition:attachment;filename=%snContent-Length:%snn" %    (os.path.split(FILENAME)[-1], len(buff))
print buff

Możesz także rozważyć odczytanie pliku przy użyciu surowego modułu IO, aby Python nie tworzył buforów tymczasowych, których nie używasz.


1 dla odpowiedzi nr 3

mod_wsgi lub FastCGI pomogłyby w tym sensienie trzeba ponownie ładować interpretera Pythona za każdym razem, gdy skrypt jest uruchamiany. Jednak niewiele by zrobiły, by poprawić wydajność odczytu pliku (jeśli to jest naprawdę twoje wąskie gardło). Radzę zamiast tego użyć czegoś podobnego do memcached.


1 dla odpowiedzi nr 4

Spróbuj odczytywać i wysyłać (tj. Buforować) fragment, powiedzmy 16 KB na raz. Prawdopodobnie Python robi coś za kulisami, a ręczne buforowanie może być szybsze.

Nie powinieneś używać np. Ramdysku - pamięć podręczna dysku systemu operacyjnego powinna za ciebie buforować zawartość pliku.