Быстрая генерация sitemap в django
Делал автоматическую генерацию sitemap.xml для сайта на джанге. На PHP без фреймворков все решалось довольно просто: printf или echo, и все попадает прямо в буфер http. Python тоже имеет такую возможность, но часто фреймворки ее исключают. В принципе это правильно.
В django есть стандартный модуль sitemaps, который генерирует карту, но он очень медленный. Для примера, если у меня 15 тысяч элементов, генерация длится почти пол минуты. Естественно такой расклад мне не понравился, так как хотелось бы отдавать карту динамически, и не нагружать при этом все на столь долгий промежуток времени.
Я пробовал генерировать через шаблон, и ручной генерацией строковой переменной. Все давало примерно тот же результат. Меньше 20 секунд не получалось. А все потому что строки в питоне не изменяются. И каждый раз при конкатенации создается новый объект. Плюс в стандартном модуле используется get_absolute_url(), который также отнимает много времени. Естественно, что чем больше строка, тем больше время создания и уничтожения. В моем случае конечный sitemap.xml получался под 2 мегабайта. А направлять вывод в поток в django нельзя. Ни в доках ни в исходниках не нашел.
Был еще вариант генерировать все в статику раз в сутки. Но я по возможности стараюсь избегать планировщиков, так как о них нужно постоянно помнить. Конечно в питоне можно просто пустить параллельным потоком при запросе любого пользователя, но вариант с динамической генерацией мне нравится больше всего.
Так же можно было попробовать использовать генератор XML, но я прикинул, что вряд ли это приведет к чему-то хорошему, и оставил эту затею.
Сначала я сделал велосипед ускоренной конкатенации строк в стиле s10=s[0]+s[1]+s[2]+..+s[9], но потом набрел в исходниках джанги на модуль StringIO. Он генерирует строку из потока, в который мы можем предварительно послать много данных. Нашел в функции демо-сервера, который выдает «Hello World!». Скорость велосипеда и StringIO почти равны, где-то около 4 секунд. Это явно лучше 30 секунд стандартного модуля. Но оказалось есть его ускоренный аналог на C — cStringIO. Он входит в поставку питона, поэтому использовал его. Правда разницы с обычным не почувствовал. Видимо уже по умолчанию используется Сишный вариант. Вот тут есть сравнение разных генераторов текста.
В целом джанга мне реально нравится больше чем пхп-фреймворки, которые я хоть когда-то видел. Все очень логично и удобно. Хотя над некоторыми вещами пришлось посидеть. Да и скорость по моим ощущениям выше. Замерами пока не занимался.
Модуль sitemap:
# Генерация строки узла def createNode(url, modified): return '<url>\ <loc>http://example.com/'+url+'</loc>\ <changefreq>weekly</changefreq>\ <lastmod>'+modified.strftime('%Y-%m-%d')+'</lastmod>\ </url>\ ' def sitemap(request): from StringIO import StringIO # Генерируем QuerySets (в принципе можно и список сгенерировать уже готовый, с сылками) qs1 = Model1.objects.filter(disabled=False) qs2 = Model2.objects.filter(disabled=False) stdout = StringIO() # Заголовочная часть XML print >>stdout, '<?xml version="1.0" encoding="utf-8"?>\ <urlset\ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"\ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\ xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9\ http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">\ ' # Генерируем сеты. Через get_absolute_url получается намного дольше, поэтому пока хардкод for item in qs1: print >>stdout, createNode('qs1/'+str(item.id), item.modified) for item in qs2: print >>stdout, createNode('qs2/'+str(item.id), item.modified) # Закрывающий тег print >>stdout, '</urlset>' xml = stdout.getvalue() # Рендерим вывод return HttpResponse(xml, mimetype="text/xml")
|
Ранее в этой же рубрике:
- Фэйл внедрения Tarantool // 22nd Февраль 2013 // 2
Свежие записи
Комментарии
- Александра: Здравствуйте. Очень полезная и интересная статья! Спасибо Вам за эту информацию.
- Hosting: Этот список неудобен для пользователей, так как им необходимо пролистать сотни вариантов, чтобы найти...
- PaNick: да, при больших нагрузках такая проблема ощущается. убрал его, когда перевалил за 10к в сутки....
- Dorian: поставили пивик лег сервер… ну очень хорошая статистика! Ещё при каждом обновлении оного апокалипсис с...
- необычный: Спасибо. Прочитал с интересом, и вообще полезный у Вас блог