#python #arrays #performance #variable-assignment #temporary
Вопрос:
Рассмотрим эти примеры с использованием Python, вызывающего несколько функций, возвращающих число, с использованием элемента массива:
import numpy as np my_array = np.zeros(looplength) for j in range(0,looplength): temp = my_first_function(j) my_array[j] = temp a_1 = my_first_function(j,temp) a_2 = my_second_function(j,temp) a_3 = my_third_function(j,temp) .... a_N = my_Nth_function(j,temp)
против
import numpy as np my_array = np.zeros(looplength) for j in range(0,looplength): my_array[j] = my_first_function(j) a_1 = my_first_function(j,my_array[j]) a_2 = my_second_function(j,my_array[j]) a_3 = my_third_function(j,my_array[j]) .... a_N = my_Nth_function(j,my_array[j])
Мой вопрос: для повышения производительности лучше ли использовать копию во временной переменной или напрямую обращаться к элементу массива, если это происходит неоднократно? Также: как часто требуется доступ к элементу массива, чтобы его копирование стало более быстрым?
Ответ №1:
Поскольку my_array
это может быть изменено внутри вызова my_lt;nthgt;_function
, компилятор не может оптимизировать каждый экземпляр my_array[j]
, и поэтому поиск должен выполняться каждый раз.
В результате извлечение значения в локальную переменную для повторного использования может работать лучше, в некоторой степени в зависимости от используемого компилятора Python и количества применений. Но я бы рискнул предположить, что все, что используется более трех раз, вероятно, того стоит, просто для производительности.
Для удобства чтения вы могли бы подумать о том, чтобы сделать это раньше, даже если есть только два варианта использования, потому что даже если это немного медленнее (создание переменной, присвоение значения, очистка), это может улучшить ваш код. Но это совсем другое дело.
Вам не нужно верить мне на слово, хотя, попробуйте это:
from timeit import timeit def number(x): return x 1 def n_times(n): a = [0, 1, 2] for i in range(n): b = number(a[1]) def n_times_copied(n): a = [0, 1, 2] x = a[1] for i in range(n): b = number(x) def main(): for n in range(10): print(f'n is {n}, access: {timeit(lambda: n_times(n))}') print(f'n is {n}, copied: {timeit(lambda: n_times_copied(n))}') main()
Мои результаты:
n is 0, access: 0.2166731 n is 0, copied: 0.22873619999999995 n is 1, access: 0.3126325000000001 n is 1, copied: 0.34623590000000004 n is 2, access: 0.4013982999999999 n is 2, copied: 0.3592341000000001 n is 3, access: 0.5191629 n is 3, copied: 0.39491809999999994 n is 4, access: 0.4818688999999998 n is 4, copied: 0.4481706000000001 n is 5, access: 0.5782233999999997 n is 5, copied: 0.5087457999999998 n is 6, access: 0.6317819 n is 6, copied: 0.5696268 n is 7, access: 0.7247358000000004 n is 7, copied: 0.6597318000000003 n is 8, access: 0.7239683000000001 n is 8, copied: 0.6870645999999994 n is 9, access: 0.8341450000000012 n is 9, copied: 0.7839662999999994
Это результаты стандартного Python 3.9.7 (который я случайно установил в своей песочнице), работающего в Windows 10 на Intel Core i9-9900K.
Обратите внимание, что существует множество вариантов (каждый вызов timeit запускает переданный вызываемый объект миллион раз), но для меня он переключается на «n равно 2» или «n равно 3», в зависимости от попытки.
Комментарии:
1. Пожалуйста, сосредоточьте свой вопрос только на вычислительной стороне, а не на моем языке. Если вы найдете какое-либо «напыщенное» выражение, не стесняйтесь изменять текст вопроса, делая его «более простым».
2. Пожалуйста, удалите эту боковую заметку. Вы улучшили суть вопроса.