Как улучшить производительность Python CGI, который читает большой файл и возвращает его в качестве загрузки? - PullRequest
2 голосов
/ 23 сентября 2009

У меня есть скрипт Python CGI, который проверяет, не обращался ли он к нему много раз с одного и того же IP-адреса, и, если все в порядке, читает большой диск с файловой формой (11 МБ), а затем возвращает его для загрузки.

Работает, но производительность отстой. Узкое место, кажется, читает этот огромный файл снова и снова:

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

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

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

Как я могу сделать это быстрее? Я думал об использовании оперативного диска для хранения файла, но должно быть какое-то лучшее решение. Поможет ли использование mod_wsgi вместо сценария cgi? Смогу ли я сохранить большой файл в памяти apache?

Любая помощь очень ценится.

Ответы [ 4 ]

9 голосов
/ 23 сентября 2009

Используйте mod_wsgi и используйте что-то похожее на:

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)

Другими словами, используйте расширение wsgi.file_wrapper стандарта WSGI, чтобы позволить Apache / mod_wsgi выполнять оптимизированный ответ содержимого файла с использованием sendfile / mmap. Другими словами, избавляет ваше приложение даже от необходимости читать файл в память.

2 голосов
/ 23 сентября 2009

Почему вы печатаете все в одном заявлении? Python должен сгенерировать несколько временных строк для обработки заголовков содержимого, и из-за этого последнего% s он должен хранить все содержимое файла в двух разных строковых переменных. Это должно быть лучше.

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

Вы можете также рассмотреть возможность чтения файла с использованием необработанного модуля ввода-вывода, чтобы Python не создавал временные буферы, которые вы не используете.

1 голос
/ 23 сентября 2009

mod_wsgi или FastCGI помогут в том смысле, что вам не нужно перезагружать интерпретатор Python при каждом запуске вашего скрипта. Тем не менее, они мало что сделают для улучшения производительности чтения файла (если это то, что действительно является вашим узким местом). Я бы посоветовал вам использовать что-то вроде memcached вместо этого.

1 голос
/ 23 сентября 2009

Попробуйте прочитать и вывести (т.е. буферизовать) порцию, скажем, 16 КБ за раз. Возможно, Python делает что-то медленное за кулисами, а ручная буферизация может быть быстрее.

Вам не нужно использовать, например, ramdisk - кеш диска ОС должен кэшировать содержимое файла для вас.

...