假设我们有一个内存密集型类,例如Image
,使用可链接的方法,例如Resize()
and ConvertTo()
.
如果这个类是不可变的,当我开始做类似的事情时,是否会占用大量内存i.Resize(500, 800).Rotate(90).ConvertTo(Gif)
,与自我修改的可变变量相比?如何用函数式语言处理这样的情况?
如果这个类是不可变的,那不是会占用大量内存吗?
通常您的内存要求对于那个单一的对象可能会加倍,因为您可能同时拥有“旧副本”和“新副本”。因此,您可以在程序的整个生命周期中将这种现象视为又分配了一个大对象与典型的命令式程序相比。 (没有被“处理”的对象只是坐在那里,与任何其他语言具有相同的内存要求。)
如何用函数式语言处理这样的情况?
绝对什么也不做。或者更准确地说,分配健康状况良好的新对象。
如果您使用的是为函数式编程设计的实现,那么分配器和垃圾收集器几乎肯定会针对高分配率进行调整,一切都会好起来的。如果您不幸尝试在 JVM 上运行函数代码,那么,性能不会像定制实现那么好,但对于大多数程序来说,它仍然很好。
你能提供更多细节吗?
当然。我将举一个非常简单的例子:1000x1000 灰度图像,每像素 8 位,旋转 180 度。这是我们所知道的:
在内存中表示图像需要 1MB。
-
如果图像是可变的,则可以通过就地更新来旋转 180 度。所需的临时空间量足以容纳一个像素。您编写了一个双重嵌套循环,相当于
for (i in columns) do
for (j in first half of rows) do {
pixel temp := a[i, j];
a[i, j] := a[width-i, height-j];
a[width-i, height-j] := tmp
}
-
如果图像是不可变的,需要创建一个全新的映像,并且暂时必须保留旧映像。代码是这样的:
new_a = Image.tabulate (width, height) (\ x y -> a[width-x, height-y])
The tabulate
函数分配一个完整的、不可变的二维数组并初始化其内容。在此操作期间,旧图像被暂时地占用内存。但当tabulate
完成,旧图像a
不应该再使用,并且它的内存现在是空闲的(也就是说,可以被垃圾收集器回收)。那么,所需的临时空间足以容纳一张图像。
当轮换进行时,不需要有其他类的对象的副本;需要临时空间only对于正在旋转的图像。
注意:对于其他操作,例如重新缩放或旋转(非方形)图像 90 度,即使图像可变,也很可能需要整个图像的临时副本,因为尺寸会发生变化。另一方面,可以使用具有非常小的临时空间的突变来完成逐像素完成的色彩空间变换和其他计算。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)