2016-05-21 1 views
9

У меня около 700 матриц, хранящихся на диске, каждая из которых содержит около 70 тыс. Строк и 300 столбцов.Memory-Mapping замедляется во времени, альтернативы?

Я должен загрузить части из этих матриц относительно быстро, около 1 тыс. Строк на матрицу, в другую матрицу, которую у меня есть в памяти. Самый быстрый способ, которым я нашел это, - использовать карты памяти, где изначально я могу загрузить 1k строк примерно за 0,02 секунды. Однако производительность не совсем согласована, и иногда загрузка занимает до 1 секунды на каждую матрицу!

Мой код выглядит следующим образом грубо:

target = np.zeros((7000, 300)) 
target.fill(-1) # allocate memory 

for path in os.listdir(folder_with_memmaps): 
    X = np.memmap(path, dtype=_DTYPE_MEMMAPS, mode='r', shape=(70000, 300)) 
    indices_in_target = ... # some magic 
    indices_in_X = ... # some magic 
    target[indices_in_target, :] = X[indices_in_X, :] 

С линией по времени линии я решил, что это, безусловно, последняя строка, которая замедляет течение долгого времени.


Upadte: Заговор время загрузки дает различные результаты. Одно время это выглядело так, то есть деградация не была постепенной, а вместо этого прыгала после 400 файлов. Может ли это быть пределом ОС?

Plot1

Но в другой раз он выглядел совсем иначе:

Plot2

После нескольких тестовых прогонов, кажется, что второй участок является довольно типичным для развития производительности.


Кроме того, я попытался del X после цикла, без какого-либо влияния. Также не удалось получить доступ к базовому Python mmap через X._mmap.close().


Любые идеи относительно того, почему существует несогласованная производительность? Существуют ли более быстрые альтернативы для хранения & для получения этих матриц?

+0

Похоже, что основной файл 'mmap' не закрывается при переходе к следующему файлу. Это дикая догадка, но я бы попробовал добавить 'del X' в конце цикла. Код для 'np.memmap' является читаемым Python, но для' mmap.mmap' нет. – hpaulj

+0

Каков диапазон индексов и они отсортированы? То есть имеет значение, если 'indices_in_X' является' np.arange (1000) 'или' np.random.shuffe (np.arange (0, 70000, 70)) '. Кроме того, попробуйте сделать тайминги независимыми от эффектов кэширования файлов ОС: http://unix.stackexchange.com/q/87908 –

+0

@morningsun Спасибо за ответ. Я попробовал сортировку 'indices_in_X', а также' indices_in_target', и я думаю, что это немного улучшает базовый уровень, но, казалось бы, случайные патчи для деградации все еще существуют. К сожалению, я работаю на общем сервере и не имею никаких привилегий sudo, поэтому я не могу очистить кеши. – fabian789

ответ

4

Жесткие диски плохо "обслуживают более одного мастера" - замедление может быть намного больше, чем можно было бы ожидать. Чтобы продемонстрировать, я использовал этот код для чтения файлов резервных копий (около 50 МБ каждый) на жестком диске моего Ubuntu 12.04 машины:

import os, random, time 

bdir = '/hdd/backup/' 
fns = os.listdir(bdir) 

while True: 
    fn = random.choice(fns) 
    if not fn.startswith("duplicity-full."): 
    continue 
    ts = time.time() 
    with open(bdir+fn, 'rb') as f: 
    c = f.read() 
    print "MB/s: %.1f" %(len(c)/(1000000*(time.time()-ts))) 

Запуск одного из этих «процессов» дает мне достойную производительность чтения:

MB/s: 148.6 
MB/s: 169.1 
MB/s: 184.1 
MB/s: 188.1 
MB/s: 185.3 
MB/s: 146.2 

Добавление второго такого процесса параллельно замедляет более, чем на порядок:

MB/s: 14.3 
MB/s: 11.6 
MB/s: 12.7 
MB/s: 8.7 
MB/s: 8.2 
MB/s: 15.9 

Моя догадка это (то есть, другое использование HDD) является причиной для inconsis палатка выступление. Моя догадка - это SSD, который будет намного лучше. Для моей машины для больших файлов на SSD замедление из-за параллельного процесса чтения было всего лишь в два раза: от примерно 440 МБ/с до 220 МБ/с. (См. Мой комментарий.)

+0

Спасибо за ввод. Я запросил доступ к серверу с SSD, посмотрю, как это происходит. – fabian789

+0

Я просто быстро проверил свой SSD с некоторыми большими файлами. Один процесс: около 440 МБ/с; со вторым процессом параллельно: около 220 МБ/с. Таким образом, SSD намного лучше, чем жесткий диск в «обслуживании двух мастеров» в этом случае. –

+0

Допустим, что поплавок (4 байта) достаточен, без сжатия 700 матриц занимают около 59 ГБ, что делает возможным решение «всей основной памяти» на мускулистом сервере. И предложение Гэри (bcolz) или другое сжатие может помочь как для решения диска, так и для основной памяти. –

4

Возможно, вы можете использовать bcolz. Он сжимает числовые данные на диске и в памяти, чтобы ускорить работу. Возможно, вам придется транспонировать матрицы, чтобы получить разреженное чтение, поскольку bcolz хранит вещи по столбцам, а не по строке.

+0

Можете ли вы показать пример использования этого? –

+0

Спасибо! Звук многообещающий. Используя SSD, я получаю довольно разумную производительность, мне нужно будет увидеть с моими супервизорами, если реализация «bcolz» теперь стоит усилий. – fabian789

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