Скорость глобальных и локальных переменных в Python

Я думаю, все знают, что:

Python обращается к локальным переменным намного эффективнее, чем к глобальным переменным.

Хорошо, это правда:

oldlist = [str(i) for i in range(500)]
oldlist1 = [i for i in range(500)]

%%timeit
newlist = []
for word in oldlist:
    newlist.append(word.upper())

10000 циклов, лучший из 3: 178 мкс на цикл

%%timeit
def func():
    newlist = []
    for word in oldlist:
        newlist.append(word.upper())
    return newlist
newlist = func()

10000 циклов, лучшее из 3: 93,2 мкс на цикл

К сожалению, похоже, что это не глобальное правило, а частный случай:

%%timeit
newlist = []
for nr in oldlist1:
    newlist.append(nr * nr)

10000 циклов, лучшее из 3: 60,3 мкс на цикл

%%timeit
def func():
    newlist = []
    for nr in oldlist1:
        newlist.append(nr * nr)
    return newlist
newlist = func()

10000 циклов, лучшее из 3: 60,5 мкс на цикл

Как можно объяснить эти тесты?


person Alexander Stavonin    schedule 19.11.2013    source источник
comment
Определение/вызов функции может замедлить работу больше, чем локальные переменные ускоряют работу.   -  person    schedule 19.11.2013
comment
Действительно, постарайтесь ограничить разницу между фрагментами кода одним изменением. Рассмотрите возможность определения функции, использующей локальную переменную, и функции, использующей глобальную переменную. Затем позвоните обоим и засеките результаты.   -  person Dennis Jaheruddin    schedule 19.11.2013
comment
Вопрос не в скорости вообще, а в локальной VS глобальной.   -  person Alexander Stavonin    schedule 19.11.2013
comment
Он предполагает, что ваш тест недостаточно изолирует переменные только от локальных до глобальных, поэтому это неправильный эксперимент. По сути, вы спрашиваете, если A должен быть медленнее, чем B, почему A + C быстрее, чем B + D, игнорируя C и D? Он говорит, что C и D нельзя игнорировать.   -  person Silas Ray    schedule 19.11.2013
comment
Да, речь идет о локальном и глобальном, но вы делаете тест глобальным и локальным + определяете функцию + вызываете функцию   -  person Alfe    schedule 19.11.2013
comment
@AlexanderStavonin: тот факт, что тесты были взяты с wiki.python.org/moin/PythonSpeed/PerformanceTips, не делает их пригодными для тестирования глобального и локального времени доступа — особенно когда они были разработаны для тестирования для циклов против понимания списка против карты.   -  person bruno desthuilliers    schedule 19.11.2013
comment
За исключением того, что в этих самых примерах используется псевдоним appendupper в этом отношении) и вызов псевдонимов внутри цикла, а не вызов их как атрибутов их родителей в каждой итерации. Эти поиски вполне могут быть более дорогостоящими, чем локальная/глобальная разница. Полученная вами дисперсия в 0,2 мкс не совсем статистически значима, учитывая, что общее значение равно 60.   -  person Silas Ray    schedule 19.11.2013
comment
Посмотрите на модуль dis. Прочитайте документацию для инструкций по байт-коду Python. Поймите, что некоторые из них намного быстрее, чем другие. например LOAD_FAST, STORE_FAST намного быстрее, чем LOAD_GLOBAL и STORE_GLOBAL. Также CALL_FUNCTION довольно медленный. Таким образом, либо LOAD_GLOBAL, STORE_GLOBAL, либо CALL_FUNCTION будут вашими узкими местами.   -  person Shashank    schedule 19.11.2013
comment
Когда у меня возникает ситуация, когда мне нужно беспокоиться о производительности, а не о читабельности, я начинаю с профилирования кода, чтобы определить потенциальное влияние изменения на производительность и избежать ухудшения читаемости кода, если я не могу добиться улучшения хотя бы на полпорядка.   -  person IceArdor    schedule 20.11.2013
comment
Использование карты или понимания списка кажется здесь уместным и, вероятно, будет работать на том же порядке, что и ваши реализации.   -  person IceArdor    schedule 20.11.2013


Ответы (1)


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

person 735Tesla    schedule 24.11.2013