2016-04-25 2 views
6

Я использую модули массивов для хранения значительных чисел (много гигабайт) беззнаковых 32-битных ints. Вместо того, чтобы использовать 4 байта для каждого элемента, python использует 8 байтов, как указано array.itemsize, и проверяется pympler.Могу ли я заставить элементы массива python иметь определенный размер?

например:

>>> array("L", range(10)).itemsize 
8 

У меня есть большое количество элементов, поэтому я хотел бы извлечь выгоду из их хранения в течение 4-х байтов.

Numpy позволит мне хранить значения как беззнаковое 32 битных целых чисел:

>>> np.array(range(10), dtype = np.uint32).itemsize 
4 

Но проблема заключается в том, что любая операция с использованием оператора индекса Numpy составляет примерно в два раза медленнее, поэтому операции, которые не являются векторные операции поддерживаются by numpy медленны. например:

python3 -m timeit -s "from array import array; a = array('L', range(1000))" "for i in range(len(a)): a[i]" 
10000 loops, best of 3: 51.4 usec per loop 

против

python3 -m timeit -s "import numpy as np; a = np.array(range(1000), dtype = np.uint32)" "for i in range(len(a)): a[i]" 
10000 loops, best of 3: 90.4 usec per loop 

Поэтому я вынужден либо использовать в два раза больше памяти, как хотелось бы, или программа будет работать в два раза медленнее, как хотелось бы. Есть ли способ обойти это? Могу ли я заставить массивы python использовать указанные элементы?

+0

https://bugs.python.org/issue26821 –

+0

Это ложная дихотомия: ваша программа может использовать меньше памяти и быть быстрее. Хотя это не связано с вопросом, можете ли вы использовать элементы массива фиксированного размера на разных платформах ('array', вероятно, использует типы C типа, родные для платформы). Это отдельный вопрос: как сделать конкретные вычисления на основе numpy быстрее. – jfs

ответ

5

Если вы хотите придерживаться использования array, set the typecode чтобы I (unsigned int), а не L (unsigned long):

>>> array.array("I", range(10)).itemsize 
4 

Тем не менее, я был бы очень удивлен, если бы не было способа ускорить ваши вычисления больше, чем 2x, которые вы теряете, используя numpy. Трудно сказать, не зная точно, что вы делаете с этими значениями.

1

2 вещи: использовать numpy.arange() (внутренний метод)

и избегать использования для операторов с Numpy (по соображениям скорости компьютера). По возможности используйте методы радиовещания.

Более простой способ получить все элементы - использовать .ravel(), если форма массива numpy мешает.

python3 -m timeit -s "import numpy as np; a = np.arange(1000), 
....... dtype = np.uint32)" "for i in range(len(a)): a[i]" 

10000 петель, лучшие из 3: 106 мксек на петле

python3 -m timeit -s "import numpy as np; a = np.arange(1000), 
....... dtype = np.uint32)" "a.ravel()" 

+1000000 петли, лучше всего 3: 0,218 мксек на петле

1

Оценка: here, array.array - это старый инструмент, который не имеет особого интереса (насколько мне известно).

Если у вас есть проблемы с эффективностью, numpy.array - лучший выбор, чем array.array, он снабжен множеством оптимизированных векторизованных инструментов. В этом случае, 32бит операции часто быстрее, чем 64бит те, даже в системе с 64 битами:

import numpy as np 
In [528]: %timeit np.sum(a32) 
1000 loops, best of 3: 1.86 ms per loop 

In [529]: %timeit np.sum(a64) 
100 loops, best of 3: 2.22 ms per loop 

In [530]: %timeit sum(a32) 
1 loop, best of 3: 572 ms per loop 

In [531]: %timeit sum(a64) 
1 loop, best of 3: 604 ms per loop 

Как вы видите, вы должны избегать чисто питона петли, которые медленнее.

Смежные вопросы