mod_wsgi возвращает выходной буфер вместо возврата - PullRequest
3 голосов
/ 30 апреля 2009

Сейчас у меня есть скрипт mod_wsgi, который структурирован так ...

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

    response_headers = [('Content-type', 'text/plain'),
                    ('Content-Length', str(len(output)))]
    start_response(status, response_headers)

    return [output]

Мне было интересно, если кто-нибудь знает способ изменить это, чтобы работать на основе yield вместо return, чтобы я мог отправлять страницу по мере ее создания, а не только после ее завершения, поэтому страница загрузка может идти быстрее для пользователя.

Однако всякий раз, когда я меняю вывод для списка и выдаю его в приложении (), он выдает ошибку:

TypeError: sequence of string values expected, value of type list found

Ответы [ 3 ]

7 голосов
/ 24 июня 2009

Обратите внимание, что «доходность» следует избегать, если в этом нет крайней необходимости. В частности, «yield» будет неэффективным, если получится множество небольших строк. Это связано с тем, что спецификация WSGI требует, чтобы после каждой полученной строки ответ очищался. Для Apache / mod_wsgi очистка означает, что каждая строка вытесняется через выходную бригаду и систему фильтрации Apache в сокет. Не обращая внимания на издержки системы выходного фильтра Apache, писать множество маленьких строк в сокет просто плохо с самого начала.

Эта проблема также существует, когда массив строк возвращается из приложения, поскольку очистка также должна выполняться между каждой строкой в ​​массиве. Это потому, что строка рассматривается как итеративная, а не как список. Таким образом, для предварительно сформированного списка строк гораздо лучше объединить отдельные строки в одну большую строку и вернуть список, содержащий только эту строку. Это также позволяет реализации WSGI автоматически генерировать Content-Length для ответа, если он не был указан явно.

Просто убедитесь, что при объединении всех строк в списке, результат возвращается в списке. Если этого не сделано и вместо этого возвращается строка, эта строка обрабатывается как итеративная, где каждый элемент в строке представляет собой строку из одного символа. Это приводит к тому, что после каждого символа выполняется очистка, что будет еще хуже, чем если бы строки не были соединены.

7 голосов
/ 30 апреля 2009
def application(environ, start_response):
    status = '200 OK'
    output = 'Hello World!'

    response_headers = [('Content-type', 'text/plain'),
                    ('Content-Length', str(len(output)))]
    start_response(status, response_headers)

    yield output

"Однако всякий раз, когда я меняю вывод для списка и выдаю его в приложении (), выдается ошибка:"

Ну, не давайте список. Вместо этого выведите каждый элемент:

for part in mylist:
    yield part

или, если список содержит весь контент, просто:

return mylist

Поскольку список уже является итератором и может выдавать сам по себе.

0 голосов
/ 04 мая 2009

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

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

    response_headers = [('Content-type', 'text/html')]
    start_response(status, response_headers)

    yield head()
    yield part1()
    yield part2()
    yield part3()
    yield "<!-- bye now! -->"

В противном случае вы не получите никакой выгоды от отправки кусками, так как вычисление вывода, вероятно, является медленной частью и Интернет-протокол все равно отправит вывод кусками.

К сожалению, это не работает в случае, когда, например, расчет of part2 () решает, что вам действительно нужно изменить заголовок (например, cookie) или нужно создавать другие структуры данных глобальной страницы - если это когда-нибудь произойдет, вам нужно вычислить весь вывод до отправка заголовков, а также может использовать return [output]

Например http://aaron.oirt.rutgers.edu/myapp/docs/W1200_1200.config_template Необходимо построить глобальную структуру данных страницы для ссылок на подразделы которые показывают в верхней части страницы - поэтому последний подраздел должен быть представлен до того, как первый блок вывода будет доставлен клиенту.

...