Зарезервировать память для списка в Python? - PullRequest
43 голосов
/ 11 февраля 2009

При программировании на Python можно ли зарезервировать память для списка, который будет заполнен известным количеством элементов, чтобы список не перераспределялся несколько раз при его создании? Я просмотрел документы по типу списка Python и не нашел ничего, что могло бы сделать это. Однако этот тип построения списка обнаруживается в нескольких горячих точках моего кода, поэтому я хочу сделать его максимально эффективным.

Редактировать: Кроме того, имеет ли смысл делать что-то подобное на таком языке, как Python? Я довольно опытный программист, но новичок в Python и все еще чувствую его способ делать вещи. Выделяет ли Python внутренне все объекты в отдельных пространствах кучи, отказываясь от попытки минимизировать выделения, или же примитивы типа int, float и т. Д. Хранятся непосредственно в списках?

Ответы [ 7 ]

34 голосов
/ 11 февраля 2009

Вот четыре варианта:

  • создание инкрементного списка
  • «предварительно выделенный» список
  • array.array ()
  • numpy.zeros ()

python -mtimeit -s"N=10**6" "a = []; app = a.append;"\
    "for i in xrange(N):  app(i);"
10 loops, best of 3: 390 msec per loop

python -mtimeit -s"N=10**6" "a = [None]*N; app = a.append;"\
    "for i in xrange(N):  a[i] = i"
10 loops, best of 3: 245 msec per loop

python -mtimeit -s"from array import array; N=10**6" "a = array('i', [0]*N)"\
    "for i in xrange(N):" "  a[i] = i"
10 loops, best of 3: 541 msec per loop

python -mtimeit -s"from numpy import zeros; N=10**6" "a = zeros(N,dtype='i')"\
    "for i in xrange(N):" "  a[i] = i"
10 loops, best of 3: 353 msec per loop

Это показывает, что [None]*N самый быстрый и array.array самый медленный в этом случае.

13 голосов
/ 11 февраля 2009

Вы можете создать список известной длины следующим образом:

>>> [None] * known_number
8 голосов
/ 13 декабря 2012

Взгляните на это:

In [7]: %timeit array.array('f', [0.0]*4000*1000)
1 loops, best of 3: 306 ms per loop

In [8]: %timeit array.array('f', [0.0])*4000*1000
100 loops, best of 3: 5.96 ms per loop

In [11]: %timeit np.zeros(4000*1000, dtype='f')
100 loops, best of 3: 6.04 ms per loop

In [9]: %timeit [0.0]*4000*1000
10 loops, best of 3: 32.4 ms per loop

Так что никогда не используйте array.array('f', [0.0]*N), используйте array.array('f', [0.0])*N или numpy.zeros.

5 голосов
/ 11 февраля 2009

В большинстве повседневных программ такая оптимизация не требуется.

Однако, когда эффективность списка становится проблемой, первое, что вы должны сделать, это заменить общий список типизированным списком из array module , что гораздо эффективнее.

Вот как можно создать список из 4 миллионов чисел с плавающей точкой:

import array
lst = array.array('f', [0.0]*4000*1000)
4 голосов
/ 11 февраля 2009

Если вы хотите эффективно манипулировать числами в Python, взгляните на NumPy ( http://numpy.scipy.org/). Это позволяет вам делать вещи очень быстро, все еще используя Python.

Чтобы делать то, что вы просите в NumPy, вы должны сделать что-то вроде

import numpy as np
myarray = np.zeros(4000)

, который даст вам массив чисел с плавающей запятой, инициализированных в ноль. Затем вы можете делать очень крутые вещи, такие как умножение целых массивов на один фактор или другие массивы и другие вещи (вроде как в Matlab, если вы когда-либо использовали это), что очень быстро (большая часть реальной работы происходит в высокооптимизированная часть C библиотеки NumPy).

Если это не массивы чисел после, то вы, вероятно, не найдете способа сделать то, что вы хотите в Python. Список объектов Python - это список точек для внутренних объектов (я так думаю, в любом случае, я не эксперт по внутренним компонентам Python), поэтому он все равно будет распределять каждый из своих элементов при их создании.

2 голосов
/ 11 февраля 2009

В Python все объекты размещаются в куче.
Но Python использует специальный распределитель памяти, поэтому malloc не будет вызываться каждый раз, когда вам нужен новый объект.
Есть также некоторые оптимизации для маленьких целых чисел (и тому подобное), которые кэшируются; однако, какие типы и как, зависит от реализации.

0 голосов
/ 12 мая 2019

для Python3:

import timeit
from numpy import zeros
from array import array

def func1():
    N=10**6
    a = []
    app = a.append
    for i in range(N):
        app(i)

def func2():
    N=10**6
    a = [None]*N
    app = a.append
    for i in range(N):
        a[i] = i

def func3():
    N=10**6
    a = array('i', [0]*N)
    for i in range(N):
        a[i] = i

def func4():
    N=10**6
    a = zeros(N,dtype='i')
    for i in range(N):
        a[i] = i

start_time = timeit.default_timer()
func1()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func2()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func3()
print(timeit.default_timer() - start_time)

start_time = timeit.default_timer()
func4()
print(timeit.default_timer() - start_time)

результат:

0.1655518
0.10920069999999998
0.1935983
0.15213890000000002
  1. Append ()
  2. [Отсутствует] * N
  3. используя массив модулей
  4. с использованием модуля numpy
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...