Подтвердить что ты не робот

Deepcopy() чрезвычайно медленный

У меня есть игровое состояние в Python с около 1000 объектами (планетарные системы + звезды + планеты), и мне нужно скопировать его и применить к нему кучу преобразований по запросу. Однако примерно в 1 запрос/секунду это занимает 24.63% от моего времени выполнения. Как я могу сделать это быстро? Обратите внимание, что копирование меньше - это не вариант, так как преобразования касаются всего всего.

РЕДАКТИРОВАТЬ: он дошел до 8% с разумной реализацией __deepcopy__ по вещам. Тем не менее, недостаточно. (Достаточно хорошо 1% или меньше, я планирую бросить еще много вещей.) timeit говорит 41.8ms за deepcopy().

4b9b3361

Ответ 1

На самом деле, глубокая копия очень медленная. Но мы можем использовать json, ujson или cPickle. мы можем использовать json/cPickle для сброса объекта и загрузить его позже. Это мой тест:

Total time: 3.46068 s
File: test_deepcopy.py
Function: test at line 15
Line #   Hits          Time Per Hit   % Time  Line Contents
==============================================================
15                                             @profile
16                                             def test():
17       100       957585   9575.9     27.7        b = deepcopy(a)
18       100          862      8.6      0.0        c = copy(a)
19       100        42295    422.9      1.2        d = ujson.loads(ujson.dumps(a))
20       100        85040    850.4      2.5        e = json.loads(json.dumps(a))
21       100      2323465  23234.7     67.1        f = pickle.loads(pickle.dumps(a, -1))
22       100        51434    514.3      1.5        g = cPickle.loads(cPickle.dumps(a, -1))

как мы можем видеть, json/ujson/cPickle быстрее, чем deepcopy, но рассол...

Ответ 2

Если вы создаете свой собственный класс для хранения этих объектов, вы можете создать свои собственные методы, которые работают с копией и глубокой копией. http://www.rafekettler.com/magicmethods.html#copying (Сломанная ссылка)

Новая ссылка для репозитория github https://github.com/RafeKettler/magicmethods

class MyClass():
    def __copy__(self):
        copy_object = MyClass()
        return copy_object

    def __deepcopy__(self, memodict={}):
        copy_object = MyClass()
        copy_object.value = self.value
        return copy_object

if __name__ == "__main__":
    my_inst = MyClass()
    print(copy.deepcopy(my_inst))

Вот аналогичное описание из предыдущей неработающей ссылки.

Копирование

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

__copy__(self)

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

__deepcopy__(self, memodict={})

Определяет поведение для copy.deepcopy() для экземпляров вашего класса. copy.deepcopy() возвращает глубокую копию вашего объекта - объект и его данные копируются. memodict - это кеш ранее скопированных объектов - это оптимизирует копирование и предотвращает бесконечную рекурсию при копировании рекурсивных структур данных. Если вы хотите глубоко скопировать отдельный атрибут, вызовите copy.deepcopy() для этого атрибута с memodict в качестве первого аргумента. Каковы некоторые примеры использования этих магических методов? Как всегда, в любом случае, когда вам нужен более мелкомасштабный контроль, чем то, что дает вам поведение по умолчанию. Например, если вы пытаетесь скопировать объект, в котором хранится кеш в качестве словаря (который может быть большим), может также не иметь смысла копировать кеш - если кеш может быть разделен в памяти между экземплярами, тогда это должно быть.

Ответ 3

Вы можете предоставить свои собственные функции копирования таким объектам, что вам не понадобится глубокая копия. глубокая копия проверяет каждый объект, чтобы проверить, что нужно скопировать. Это дорогостоящая операция.