Понадобилось мне как-то сделать из таблички в питоне html. Табличка объемная вопрос оптимизации важен.
А тут на хабре статья забавная появилась. Там в комментах рекомендуют использовать ''.join(list) вместо str += str.
Решил последовать совету и переписал свою функцию. А теперь самое интересное: соединение юникодных строк происходит действительно раз в 10 быстрее, но вот для ansi-строк проигрывает. Хотелось бы узнать почему так?
Вот полный код теста:
from time import time
printHeader = """
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/></head>
<body><h1>%s</h1><table cellspacing="0" cellpadding="0">
"""
s1 = (u'Тест', u'Еще тест')*8
s1 = [i.encode('cp1251') for i in s1]
s2 = [s1]*500
def table2html1(src, s1, printHeader):
s = printHeader % 'dfgsdfgsdfg'
s += '<tr>'for col in s1:
s += '<td>%s </td>'%col
s += '</tr>\n'for row in src:
s += '<tr>'for col in row:
s += '<td>%s </td>'%col
s += '</tr>\n'
s += "</table></body></html>"return s
def table2html2(src, s1, printHeader):
mkRow = lambda row: ''.join(sum((('<td>', col, ' </td>') for col in row), ()))
mkDoc = lambda doc: ''.join(sum((('<tr>', mkRow(row), '</tr>\n') for row in doc), ()))
return''.join((printHeader % 'dfgsdfgsdfg', mkDoc([s1]), mkDoc(src), '</table></body></html>'))
from cStringIO import StringIO
def table2html3(src, s1, printHeader):
s = StringIO()
s.write(printHeader % 'dfgsdfgsdfg')
def mkDoc(doc):
for row in doc:
s.write('<tr>')
for col in row:
s.write('<td>')
s.write(col)
s.write(' </td>')
s.write('</tr>\n')
mkDoc([s1])
mkDoc(src)
s.write("</table></body></html>")
return s.getvalue()
t = time()
result1 = table2html1(s2, s1, printHeader)
print time()-t
t = time()
result2 = table2html2(s2, s1, printHeader)
print time()-t
t = time()
result3 = table2html3(s2, s1, printHeader)
print time()-t
with open('join1.html', 'wb') as fd:
fd.write(result1)
with open('join2.html', 'wb') as fd:
fd.write(result2)
with open('join3.html', 'wb') as fd:
fd.write(result3)
Тут еще одна версия есть с использованием cStringIO — table2html3.
Результаты:
0.00999999046326
0.0150001049042
0.0190000534058
Если закоментировать вверху s1 = [i.encode('cp1251') for i in s1]:
0.648000001907
0.018000125885
Traceback (most recent call last): # cStringIO с юникодом не работает, нужно оставить StringIO, но он медленнее.
Или я что-то упустил?
Re: [Python] Оптимизация соединения множества строк
Здравствуйте, Critical Error, Вы писали:
CE>Понадобилось мне как-то сделать из таблички в питоне html. Табличка объемная вопрос оптимизации важен.
Полуофф в помощь. В закромах ссылочка завалялась Efficient String Concatenation in Python http://www.skymind.com/~ocrow/python_string/ (т.к. дата публикации 2004-05-01, имеет смысл перепроверить инфу в ней)
Хорошо там, где мы есть! :)
Re: [Python] Оптимизация соединения множества строк
CE>Понадобилось мне как-то сделать из таблички в питоне html. Табличка объемная вопрос оптимизации важен.
CE>А тут на хабре статья забавная появилась. Там в комментах рекомендуют использовать ''.join(list) вместо str += str.
CE>Решил последовать совету и переписал свою функцию. А теперь самое интересное: соединение юникодных строк происходит действительно раз в 10 быстрее, но вот для ansi-строк проигрывает. Хотелось бы узнать почему так?
CE>Если закоментировать вверху s1 = [i.encode('cp1251') for i in s1]:
Если s1 будет юникодом, то и джойнить надо тоже юникодовой строкой.
u"".join(...)
Иначе происходит неявное кодирование, которое может быть причиной медленности.
Здравствуйте, Temoto, Вы писали:
T>Если s1 будет юникодом, то и джойнить надо тоже юникодовой строкой.
T>u"".join(...)
T>Иначе происходит неявное кодирование, которое может быть причиной медленности.
def table2html1u(src, s1, printHeader):
s = printHeader % 'dfgsdfgsdfg'
s = s.decode('utf-8')
s += u'<tr>'for col in s1:
s += u'<td>%s </td>'%col
s += u'</tr>\n'for row in src:
s += u'<tr>'for col in row:
s += u'<td>%s </td>'%col
s += u'</tr>\n'
s += u"</table></body></html>"return s
Результат тот же. В общем я сделал вывод, что внутри питона операция += хорошо оптимизирована только для ANSI-строк, в то время как для unicode она выполняется по канонам неизменных строк, то есть sNew = sOld1 + sOld2 с дереференсом обоих старых строк и чисткой sOld1 после завершения операции.
В общем я выбираю вариант с join — он хоть и чуток медленнее, но зато скорость работы не зависит от типа выбранных строк.
T>Вообще же, для решения вашей задачи хорошо подходит (2.5 и ниже) string.format, (2.6 и выше) str/unicode.format, mako http://www.makotemplates.org/ , Jinja2 http://jinja.pocoo.org/2/
Шаблонный двиг использовать для этой простенькой задачки считаю не слишком эффективным.
Re[3]: [Python] Оптимизация соединения множества строк
CE>Результат тот же. В общем я сделал вывод, что внутри питона операция += хорошо оптимизирована только для ANSI-строк, в то время как для unicode она выполняется по канонам неизменных строк, то есть sNew = sOld1 + sOld2 с дереференсом обоих старых строк и чисткой sOld1 после завершения операции.
CE>В общем я выбираю вариант с join — он хоть и чуток медленнее, но зато скорость работы не зависит от типа выбранных строк.
Увышка, я думал будет разница.
T>>Вообще же, для решения вашей задачи хорошо подходит (2.5 и ниже) string.format, (2.6 и выше) str/unicode.format, mako http://www.makotemplates.org/ , Jinja2 http://jinja.pocoo.org/2/
CE>Шаблонный двиг использовать для этой простенькой задачки считаю не слишком эффективным.
Эффективность меряется не "считаю" или простотой задачи, а бенчмарками. Вы же не знаете как эти движки реализованы. Может быть они быстрее отработают, чем += или даже join.
В качестве бонуса получите поддерживаемый код, с которым во много раз удобнее работать, чем с этим ужасом из циклов и кавычек.
Re[2]: [Python] Оптимизация соединения множества строк
Здравствуйте, Temoto, Вы писали:
T>Вообще же, для решения вашей задачи хорошо подходит (2.5 и ниже) string.format, (2.6 и выше) str/unicode.format, mako http://www.makotemplates.org/ , Jinja2 http://jinja.pocoo.org/2/
Провел дополнительно тест для DTL:
def table2htmlDTL(src, s1, printHeader):
tmpl = Template("""<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251"/></head>
<body><h1>{{ hh }}</h1><table cellspacing="0" cellpadding="0">
{% for row in tbl %}
<tr>{% for col in row %}<td>{{ col }} </td>{% endfor %}</tr>
{% endfor %}
</table></body></html>""")
c = Context({"hh": 'dfgsdfgsdfg', 'tbl': src})
return tmpl.render(c)
Результат для ANSI и unicode одинаков: 0.75, то есть сравним с соединением операцией += для unicode. Зато код красивый и универсальный.
Re[4]: [Python] Оптимизация соединения множества строк
Здравствуйте, Temoto, Вы писали:
T>Эффективность меряется не "считаю" или простотой задачи, а бенчмарками. Вы же не знаете как эти движки реализованы. Может быть они быстрее отработают, чем += или даже join.
T>В качестве бонуса получите поддерживаемый код, с которым во много раз удобнее работать, чем с этим ужасом из циклов и кавычек.
Тест для DTL я привел ранее, он оказался медленнее. Но код красив, да...
Дело в том что это добавит зависимость в довольно простой код. Эту зависимость придется тянуть с моей программой постоянно. К тому же чудес не бывает... Шаблонизаторы внутри устроены примерно одинаково: сначала происходит разбивка на токены скорее всего регулярными выражениями, затем подставляются переменные и происходит тот же самый join. Конечно всякое бывает, но врядли есть схема быстрее этой на питоне... Насколько я понял по исходникам, именно так работает DTL.
Re[3]: [Python] Оптимизация соединения множества строк
Здравствуйте, Critical Error, Вы писали:
CE>Результат для ANSI и unicode одинаков: 0.75, то есть сравним с соединением операцией += для unicode. Зато код красивый и универсальный.
Ошибочка. DTL не работает с ANSI, на месте полей в табличке оказалось пусто.
Re[5]: [Python] Оптимизация соединения множества строк
T>>Эффективность меряется не "считаю" или простотой задачи, а бенчмарками. Вы же не знаете как эти движки реализованы. Может быть они быстрее отработают, чем += или даже join.
T>>В качестве бонуса получите поддерживаемый код, с которым во много раз удобнее работать, чем с этим ужасом из циклов и кавычек.
CE>Тест для DTL я привел ранее, он оказался медленнее. Но код красив, да...
CE>Дело в том что это добавит зависимость в довольно простой код. Эту зависимость придется тянуть с моей программой постоянно. К тому же чудес не бывает... Шаблонизаторы внутри устроены примерно одинаково: сначала происходит разбивка на токены скорее всего регулярными выражениями, затем подставляются переменные и происходит тот же самый join. Конечно всякое бывает, но врядли есть схема быстрее этой на питоне... Насколько я понял по исходникам, именно так работает DTL.
Именно поэтому я не советовал тормозную Django. Посоветовал несколько конкретных решений, которые знамениты скоростью.
Re[6]: [Python] Оптимизация соединения множества строк
Здравствуйте, Temoto, Вы писали:
T>Именно поэтому я не советовал тормозную Django. Посоветовал несколько конкретных решений, которые знамениты скоростью.
Хм, и правда, Jinja2 выдала очень хороший результат, раз в 30 быстрее DTL. При этом код шаблона остался таким же.