deepcopy()非常慢

Ele*_*tro 26 python optimization deep-copy

我在Python中有一个游戏状态,有大约1000个对象(行星系统+星星+行星),我需要复制它并在请求时应用一堆变换.但是,在大约1个请求/秒时,这占我运行时的24.63%.我怎样才能让它变得快速?请注意,复制较少不是一个选项,因为变换几乎触及所有内容.

编辑:通过明智的实施来降低到8%__deepcopy__.不过,还不够好.(足够好是1%或更少,我计划在此投掷更多的东西.)timeit说每个41.8ms deepcopy().

che*_*ish 35

实际上,深度显示非常慢.但我们可以使用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))
Run Code Online (Sandbox Code Playgroud)

正如我们所看到的,json/ujson/cPickle比deepcopy更快,但是pickle ......

  • 请注意,对于 python3,“pickle” 是此处列出的“cPickle”。 (6认同)
  • 我做了一些测试,发现deepcopy在字典列表上的表现优于json,而json在大型嵌套字典上的表现优于deepcopy. (4认同)
  • 小心`json.loads(json.dumps(a))`(可能也适用于`ujson`),它们总是将键视为字符串。如果键不是字符串,它将转换为字符串。 (4认同)
  • 我不知道......你可以找到有用的东西[这里](https://docs.python.org/2/library/copy.html):) (2认同)

jus*_*gel 5

如果创建自己的类来容纳这些对象,则可以创建自己的用于复制和深度复制的方法。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))
Run Code Online (Sandbox Code Playgroud)

这是来自先前断开链接的类似描述。

复制中

有时,尤其是在处理可变对象时,您希望能够复制对象并进行更改而不影响复制对象。这就是Python副本发挥作用的地方。但是(幸运的是),Python模块不是有感觉的,因此我们不必担心基于Linux的机器人起义,但是我们必须告诉Python如何有效地复制内容。

__copy__(self)

为类的实例定义copy.copy()的行为。copy.copy()返回对象的浅表副本-这意味着,尽管实例本身是一个新实例,但其所有数据都被引用了-即,对象本身已被复制,但其数据仍被引用了(因此更改浅表副本中的数据可能会导致原始文件的更改)。

__deepcopy__(self, memodict={})

为类的实例定义copy.deepcopy()的行为。copy.deepcopy()返回对象的深层副本-对象及其数据均被复制。memodict是先前复制对象的缓存-优化复制并防止在复制递归数据结构时进行无限递归。当您想深层复制单个属性时,请以该属性作为第一个参数调用该属性的copy.deepcopy()。这些魔术方法有哪些用例?与往常一样,在任何情况下,您需要比默认行为所提供的控制更多的细粒度控制。例如,如果您尝试复制一个将缓存存储为字典的对象(可能很大),那么复制缓存也可能没有意义-如果可以在实例之间的内存中共享缓存,则它应该是。


Bor*_*ort 1

您可以为对象提供自己的复制函数,这样您就不需要深层复制。深复制检查每个对象以检查需要复制的内容。这是一项昂贵的操作。

  • 是的,“deepcopy()”必须确保不会出现引用循环等......还涉及很多簿记工作。请参阅[此处](http://stackoverflow.com/questions/3043369/deepcopy-and-python-tips-to-avoid-using-it),[此处](http://stackoverflow.com/questions/10128351/ any-alternative-to-a-very-slow-deepcopy-in-a-dfs)和[此处](http://writeonly.wordpress.com/2009/05/07/deepcopy-is-a-pig-for -简单数据/)。 (2认同)