Краткий ответ
Только массив roix
является c_contiguous. Таким образом, передача по шине из памяти в ЦП происходит быстрее, чем для несмежных данных (из-за того, что шина перемещает данные в чанке и кэширует их)
Вы можете получить небольшое улучшение (около 5% для роиза и 40% для роя), сделав его непрерывным C np.save(file, np.asarray(a, order='C'))
Больше объяснений
Профилирование
Вы должны использовать timeit для определения времени ваших выступлений вместо пользовательских методов.
Я сделал их, чтобы вы показали пример:
В клетку попали:
import os
import numpy as np
import time
import matplotlib.pyplot as plt
# take a slice of the data
def slice_data(roi):
dic = {}
data = np.zeros((512,512,256))
dic['data'] = np.squeeze( data[roi[0]:roi[1]+1, roi[2]:roi[3]+1, roi[4]:roi[5]+1] )
return dic
# save slices if the data
def save_slices(roi, save=False):
var = 'data'
for i in range(0,6):
# iterate to simulate a time series of data
a = slice_data(roi)[var]
var_dir = 'save_test/'
if not os.path.exists(var_dir): os.makedirs(var_dir)
file = var_dir + '{0:04d}{1}'.format(i,'.npy')
if save is True:
np.save(file, a)
## define slices
roix=[256, 256, 0, 512, 0, 256] # yz plane slice
roiy=[0, 512, 256, 256, 0, 256] # xz plane slice
roiz=[0, 512, 0, 512, 128, 128] # xy plane slice
в других:
%%timeit -n 100
save_slices(roix) # 19.8 ms ± 285 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit -n 100
save_slices(roiy) # 20.5 ms ± 948 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit -n 100
save_slices(roiz) # 20 ms ± 345 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
С сохранением
%%timeit -n 10 -r 3
save_slices(roix, True) # 32.7 ms ± 2.31 ms per loop (mean ± std. dev. of 3 runs, 10 loops each)
%%timeit -n 10 -r 3
save_slices(roiy, True) # 101 ms ± 2.61 ms per loop (mean ± std. dev. of 3 runs, 10 loops each)
%%timeit -n 10 -r 3
save_slices(roix, True) # 1.9 s ± 21.1 ms per loop (mean ± std. dev. of 3 runs, 10 loops each)
Итак, как вы уже заметили, без сохранения показатели одинаковы!
Давайте познакомимся с методом np.save()
Np.save метод
np.save
заботится о потоковой передаче io и вызывает метод write_array . Что действительно быстро для массива C_contigous. (Быстрый доступ к памяти)
Давайте проверим эту гипотезу:
np.squeeze( np.zeros((512,512,256))[roix[0]:roix[1]+1, roix[2]:roix[3]+1, roix[4]:roix[5]+1] ).flags.c_contiguous # returns True
np.squeeze( np.zeros((512,512,256))[roiy[0]:roiy[1]+1, roiy[2]:roiy[3]+1, roiy[4]:roiy[5]+1] ).flags.c_contiguous # returns False
np.squeeze( np.zeros((512,512,256))[roiz[0]:roiz[1]+1, roiz[2]:roiz[3]+1, roiz[4]:roiz[5]+1] ).flags.c_contiguous # returns False
Так что это может объяснить разницу между roix
и roiy
/ roiz
.
Потенциальное объяснение разницы между roiy
и roiz
. Передача данных замедляет работу программы
После этого я мог только делать предположения, roiz
кажется гораздо более фрагментированным, чем roiy
. Что занимает много времени для метода write_array
.
Я не могу проверить это сам сейчас, но эту часть можно проверить с помощью команды perf
в linux. (Чтобы увидеть количество использованных шин, например, количество пропущенных кешей).
Если бы мне пришлось делать дикие предположения, я бы сказал, что ошибки кэширования довольно высоки из-за того, что данные не являются смежными. Таким образом, передача данных из ОЗУ в ЦП действительно замедляет процесс.
Другие способы обращения с хранилищем
Я не пробовал, но есть хороший вопрос с несколькими полезными ответами: лучший способ сохранить массивы на диске