Eleneldil G. Arilou (arilou) wrote,
Eleneldil G. Arilou
arilou

Питон, строки, продолжаю измерять.

В продолжение предыдущего поста
Взявшись убрать из кода пару-тройку свеже вписанных str.format, задумался и о скорости сцепки коротких строк.

Первые приходящие в голову способы:
1) %-форматирование
2) "Сложение" строк (str1 + str2)
3) ''.join(seq)
Третий способ бесспорно удобен, когда seq (кортеж, список, итератор) в нужном порядке у нас уже готов. А если есть отдельные строки, то он выглядит уже менее красиво: ''.join((str1, str2)). Однако, в книжках было написано, что ''.join имеет то преимущество перед "сложением", что при сцепке более двух строк не создаёт промежуточные результаты.

Беру в руки секуномер...

from timeit import timeit as ti, repeat as tir
>>> def ti_cmp(stmt1, stmt2, rep=6):
... return map(lambda x, y: '%.4f' % (x / y), tir(stmt1, repeat=rep) , tir(stmt2, repeat=rep))
...

Замеряю...

>>> ti("'`%s`' % 'qwerty'") / ti ("''.join(('`', 'qwerty', '`'))")
0.15900281982625888

Получается, на мелких сцепках ''.join вреден.

>>> ti_cmp("'`%s`' % 'qwerty'", "'`' + 'qwerty' + '`'")
['1.0109', '1.0030', '0.9626', '0.9643', '1.0066', '0.9976']

Тут практически одинаково. Но чуть усложним, и...

>>> ti_cmp("'`%s` as `%s`' % ('qwerty', 'qqq')", "'`' + 'qwerty' + '` as `' + 'qqq' + '`'")
['6.9943', '6.9009', '6.9742', '6.9735', '6.8879', '6.9646']
>>> ti_cmp("'`%s` as `%s`' % ('qwerty', 'qqq')", "''.join(('`','qwerty','` as `','qqq','`'))")
['0.8639', '0.8592', '0.9210', '0.8885', '0.8638', '0.8628']

Форматирование безнадёжно проигрывает "сложению", хотя ещё выигрывает у ''.join.
Заодно проверил, что будет, если кортеж для ''.join заготовить заранее:

>>> tpl = ('`','qwerty','` as `','qqq','`')
>>> ti("''.join(tpl)", "from __main__ import tpl") / ti ("''.join(('`', 'qwerty', '` as `', 'qqq', '`'))")
1.0001781231845137
>>> ti("''.join(tpl)", "from __main__ import tpl") / ti ("''.join(('`', 'qwerty', '` as `', 'qqq', '`'))")
0.99115275922939039

Т.е. практически без разницы, поиск переменной tpl занимает время, сравнимое с временем создания небольшого кортежа на лету.

И того, на маленьких строках "сложение" уверенно лидирует, хотя в совсем коротком случае %-форматирование даёт тот же результат.

Где же ужасы создания промежуточных строк при "сложении"?

>>> ti ("'`' + 'qwerty' + '` as `' + 'qqq' + '`'") / ti ("''.join(('`', 'qwerty', '` as `', 'qqq', '`'))")
0.1214502923338789
>>> ti ("'`' + 'qwertyqwertyqwerty' + '` as `' + 'qqq' + '`'") / ti ("''.join(('`', 'qwertyqwertyqwerty', '` as `', 'qqq', '`'))")
0.71356679587553884
>>> ti ("'SELECT `' + 'qwertyqwertyqwerty' + '` as `' + 'qqq' + '`'") / ti ("''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '`'))")
0.97721257775680759
>>> ti ("'SELECT `' + 'qwertyqwertyqwerty' + '` as `' + 'qqq' + '` FROM DB'") / ti ("''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB'))")
1.0434518569843669
>>> ti("'SELECT `' + 'qwertyqwertyqwerty' + '` as `' + 'qqq' + '` FROM DB WHERE `' + 'a' + '` = 0'") / ti("''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB WHERE `', 'a', '` = 0'))")
1.3793693084449092
>>> ti("'SELECT `' + 'qwertyqwertyqwerty' + '` as `' + 'qqq' + '` FROM DB WHERE `' + 'a' + '` = 0' + ' '") / ti("''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB WHERE `', 'a', '` = 0', ' '))")
1.5511805115507227

Ну, вот и они.
А как насчёт %-форматирования на таких строках?

>>> ti_cmp("'SELECT `%s` as `%s` FROM DB WHERE `%s` = 0' % ('qwertyqwertyqwerty','qqq','a')", "''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB WHERE `', 'a', '` = 0'))")
['1.0474', '1.0977', '1.0814', '1.0722', '1.0698', '1.0829']
>>> ti_cmp("'SELECT `%s` as `%s` FROM DB WHERE `%s` = %d' % ('qwertyqwertyqwerty','qqq','a',0)", "''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB WHERE `', 'a', '` = ', str(0)))")
['1.4546', '1.4273', '1.4362', '1.4385', '1.4560', '1.4595']
>>> ti_cmp("'SELECT `%s` as `%s` FROM DB WHERE `%s` = %d' % ('qwertyqwertyqwerty','qqq','a',0)", "''.join(('SELECT `', 'qwertyqwertyqwerty', '` as `', 'qqq', '` FROM DB WHERE `', 'a', '` = ', format(0, 'd')))")
['1.0202', '1.0167', '1.0175', '1.0276', '1.0193', '1.0053']

Уступает join'у свосем немного. При этом читабельность, я думаю, всё же лучше. (Использование явного форматирования числа как числа, конечно, снижает скорость, но это уже порой необходимость.)


This entry was originally posted at http://arilou.dreamwidth.org/904516.html. Please comment there using OpenID.
Tags: python, программирование
Subscribe
  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 0 comments