Deepcopy() чрезвычайно медленный
У меня есть игровое состояние в Python с около 1000 объектами (планетарные системы + звезды + планеты), и мне нужно скопировать его и применить к нему кучу преобразований по запросу. Однако примерно в 1 запрос/секунду это занимает 24.63% от моего времени выполнения. Как я могу сделать это быстро? Обратите внимание, что копирование меньше - это не вариант, так как преобразования касаются всего всего.
РЕДАКТИРОВАТЬ: он дошел до 8% с разумной реализацией __deepcopy__
по вещам. Тем не менее, недостаточно. (Достаточно хорошо 1% или меньше, я планирую бросить еще много вещей.) timeit
говорит 41.8ms за deepcopy()
.
Ответы
Ответ 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
Вы можете предоставить свои собственные функции копирования таким объектам, что вам не понадобится глубокая копия. глубокая копия проверяет каждый объект, чтобы проверить, что нужно скопировать. Это дорогостоящая операция.