我在一些 Rebol 代码中发现了这样的一行:
dups: make block! 10000
为什么要在 Rebol 中使用预分配?
只写有什么问题:
dups: copy []
我在一些 Rebol 代码中发现了这样的一行:
dups: make block! 10000
为什么要在 Rebol 中使用预分配?
只写有什么问题:
dups: copy []
第一件事:你不会在 Rebol 中“分配一个变量”,而是“预先分配一个系列缓冲区”(它恰好被代码示例中的一个单词引用,但它可能只是位于一个块中)。
快速回答:每次您将数据插入或追加到系列时,如果系列缓冲区已满,则内存管理器会将系列重新分配给更大的缓冲区。如果您多次扩展一个系列(例如在循环中将数据附加到系列),如果您不预先分配,您最终可能会为所有重新分配消耗大量额外内存,并且可能在某个时候,也触发垃圾收集器通道。这通常会导致程序执行速度大大减慢并消耗大量额外内存。将系列缓冲区预分配到足够大的大小以容纳所有最终数据,将避免所有这些内存和性能问题。
在 的情况下dups: copy []
,您正在分配一个最小系列缓冲区(大小可能为 8 或 16 个插槽),因此如果您的所有数据都不适合此缓冲区,您的程序将支付重新分配的(沉重)成本( s)。也是[]
一个预先分配的最小大小的文字系列,您只是将其用作构建新系列的模板,因此最好避免浪费内存并改为编写:dups: make block! 0
这将分配一个块!系列最小尺寸,不浪费额外的块!系列。
预分配缓冲区对于低级函数 read-io 是必不可少的
如果您需要例如在读取数据时访问确切的错误代码,您可以使用 read-io 而不是在打开的端口上复制。
read-io 与 c 语言中的 READ 相当。您为 read-io 提供了预先分配的固定缓冲区和缓冲区长度。如果您尝试使用超过预先分配的缓冲区长度的 read-io,您将自行承担风险
我刚测试
>> a: make block! 10000
>> b: copy []
>> delta-time [loop 10000 [append a 1]]
== 0:00:00.004315
>> delta-time [loop 10000 [append b 1]]
== 0:00:00.005795
差别只是不到百分之一秒。
然后我重新启动 rebol 并测试:
>> a: make block! 10000
>> b: copy []
>> delta-time [loop 20000 [append a "test"]]
== 0:00:00.000238
>> delta-time [loop 20000 [append b "test"]]
== 0:00:00.000223
没有预分配比预分配更快!
我同意 Ladislav 的观点,即增量时间可能不可靠。但是我不认为现代 PC 需要预先分配,一个简单的浏览器插件会浪费大量内存。我相信 Rebol 垃圾收集器对于普通使用来说已经足够了。(可能在Android设备速度和内存上还是有问题的)