Как выбрать объекты с несколькими представлениями одного и того же представления памяти Cython - PullRequest
2 голосов
/ 11 октября 2019

У меня есть несколько объектов, которые я пытаюсь выбрать, и все они имеют одинаковое (большое) представление памяти Cython в качестве атрибута. Поскольку просмотры памяти передаются по ссылке, они все используют одну и ту же память, а реализация эффективна для использования памяти.

Теперь мне нужно выбрать эти объекты и перезагрузить их, сохраняя при этом общие данные общими (если общие данные не становятсяподелился, после чего размер файла увеличивается, и невозможно прочитать в память). Обычно я думаю, что pickle распознает общие данные и просто обрабатывает их один раз, но из-за того, что представления памяти не могут быть обработаны напрямую, их необходимо преобразовать в массив numpy в методе redu для каждого объекта и метода pickle. больше не признает, что данные являются общими.

Есть ли какой-нибудь способ, которым я могу поддерживать общие данные с помощью процесса выбора / рассортировки?

Далее следует MWE:

import numpy as np    
import pickle

cdef class SharedMemory:  
    cdef public double[:, :] data

    def __init__(self, data):   
        self.data = data

    def duplicate(self):
        return SharedMemory(self.data)

    def __reduce__(self):   
        return self.__class__, (np.asarray(self.data),)


def main():   
    x = SharedMemory(np.random.randn(100, 100))

    duplicates = [x.duplicate() for _ in range(5)]

    cdef double* pointerx = &x.data[0, 0]
    cdef double* pointerd
    cdef double[:, :] ddata

    for d in duplicates:
        ddata = d.data 
        pointerd = &ddata[0, 0]
        if pointerd != pointerx:
            print('Memory is not shared')
        else:
            print('Memory is shared')

    print('pickling')
    with open('./temp.pickle', 'wb') as pfile:
        pickle.dump(x, pfile, protocol=pickle.HIGHEST_PROTOCOL)
        for d in duplicates:
            pickle.dump(d, pfile, protocol=pickle.HIGHEST_PROTOCOL)

    with open('./temp.pickle', 'rb') as pfile:
        nx = pickle.load(pfile)
        nd = []
        for d in duplicates:
            nd.append(pickle.load(pfile))

    ddata = nx.data
    cdef double* pointernx = &ddata[0, 0]

    for d in nd:
        ddata = d.data
        pointerd = &ddata[0, 0]
        if pointerd != pointernx:
            print('Memory is not shared')
        else:
            print('Memory is shared')

Поместите вышеуказанное в тест файла.pyx - цитонизировать с помощью «cythonize -a -i test.pyx». Затем "export PYTHONPATH =" $ PYTHONPATH ":."и запустите

from test import main
main()

из Python.

1 Ответ

2 голосов
/ 11 октября 2019

На самом деле есть две проблемы:

Первое: Общие объекты также распределяются после дампа / загрузки только в том случае, если они были протравлены за один проход (см. Также этот ответ ).

Это означает, что вам нужно сделать следующее (или подобное):

...
with open('./temp.pickle', 'wb') as pfile:
     pickle.dump((x,duplicates), pfile, protocol=pickle.HIGHEST_PROTOCOL)
...
with open('./temp.pickle', 'rb') as pfile:
     nx, nd = pickle.load(pfile)
...

Когда вы сбрасываете одиночные объекты, pickle не может отслеживать идентичные объекты - это будет проблемой: объекты с одинаковым идентификатором между двумя dump -требованиями могут быть совершенно разными объектами или одинаковыми объектами с разным содержимым!

Секунда: Вы не должны создавать новые объекты, но должны передаватьобщий numpy-объект в __reduce__ (pickle не заглядывает внутрь numpy-массива, чтобы увидеть, является ли буфер общим или нет, но только по идентификатору массива):

def __reduce__(self):
    return self.__class__, (self.data.base,)

, которыйдаст вам желаемый результат. data.base - это ссылка на исходный исходный массив numpy (или любой другой тип, который, очевидно, должен поддерживать травление / расщепление).


Предупреждение: Как верно @DavidWуказал, что при работе с нарезанными представлениями памяти необходимо учитывать дополнительные соображения, поскольку в этом случае base может не совпадать с фактическим представлением памяти.

...