Принудительная передача по ссылке в Python - PullRequest
1 голос
/ 21 июля 2011

Мальчик, я не понимаю проблем с передачей по ссылке в Python ... Я создал чрезвычайно полезный класс "unpacker", который я передаю различным объектам, которые нужно распаковать из него, но учитывая, насколько он чрезвычайно медленныйЯ могу сказать, что он делает копию binaryStr каждый раз, когда я передаю объект BU.Я знаю это, потому что если я разбиваю BU на более мелкие куски, он работает буквально в 100 раз быстрее (я изначально использовал его для хранения 16 МБ буферного файла ввода-вывода)

Итак, мой вопрос, почему это так?член не передается по ссылке, и есть ли способ заставить его?Я почти уверен, что сам объект BU передается по ссылке (поскольку мой код работает), но скорость предполагает, что объект .binaryStr скопирован.Есть ли что-то более тонкое, что я упускаю?

class BinaryUnpacker(object):
    def __init__(self, binaryStr):
        self.binaryStr = binaryStr
        self.pos = 0

    def get(self, varType, sz=0):
        pos = self.pos
        if varType == UINT32:
            value = unpack('<I', self.binaryStr[pos:pos+4])[0]
            self.pos += 4
            return value
        elif varType == UINT64:
            value = unpack('<Q', self.binaryStr[pos:pos+8])[0]
            self.pos += 8
            return value
        elif varType == VAR_INT:
            [value, nBytes] = unpackVarInt(self.binaryStr[pos:])
            self.pos += nBytes
        ....

Вариант использования для этого - что-то вроде:

def unserialize(self, toUnpack):
    if isinstance(toUnpack, BinaryUnpacker):
        buData = toUnpack
    else:  # assume string
        buData = BinaryUnpacker(toUnpack)

    self.var1    = buData.get(VAR_INT)
    self.var2    = buData.get(BINARY_CHUNK, 64)
    self.var3    = buData.get(UINT64)
    self.var4obj = AnotherClass().unserialize(buData)

Большое спасибо за вашу помощь.

Ответы [ 3 ]

4 голосов
/ 21 июля 2011

Копии создаются, когда вы разрезаете строку, чтобы получить подстроку.Например:

[value, nBytes] = unpackVarInt(self.binaryStr[pos:])

Это создаст копию строки из индекса pos до конца, что может занять некоторое время для длинной строки.Это будет быстрее, если вы сможете определить количество байтов, которое вам действительно нужно, прежде чем брать подстроку, а затем использовать self.binaryStr[pos:pos+nBytes], поскольку получение небольшой подстроки относительно быстро.

Обратите внимание, что время зависит только отдлина подстроки, поэтому self.binaryStr[pos:pos+4] должно занимать примерно одинаковое количество времени независимо от длины self.binaryStr.

3 голосов
/ 21 июля 2011

Я не посмотрел ваш код подробно, но к типам, которые предоставляют метод buffer() (например, строки), можно получить доступ с помощью memoryview objects без необходимости копировать данные. Вот соответствующая документация для него.

Вы можете использовать объект memoryview вместо разрезания строки: таким образом вы обойдете трудоемкий проход текущего кода.

Несколько дней назад я задал вопрос об этом, который, возможно, может быть полезен для вас.

0 голосов
/ 21 июля 2011

Я не думаю, что судить просто по скорости - это правильно. Вы сказали, что можете сказать, что строка копируется, потому что если вы разбиваете ее на более мелкие фрагменты, она работает намного быстрее. Но время выполнения функции unpack (), о которой вы не указали детали, также может зависеть от размера данных.

Кроме того, нарезая строку, такую ​​как

unpack('<I', self.binaryStr[pos:pos+4])[0]

создаст новые строковые объекты, поскольку строки являются неизменяемыми объектами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...