在大数组中使用推送与cont的性能含义主要是由于这些方法处理数组合并或元素添加的不同方式以及它们的基础内存管理和计算开销。
使用array.push时,一个数组中的元素直接附加到现有数组。为了合并数组,这通常涉及一个模式,例如使用Apply或传播操作员立即推动多个元素,例如Array.prototype.push.apply(ARR1,ARR2)。此方法修改了原始数组,通常以线性时间O(n)执行,其中n是要按下的元素数量。原因是将元素通常添加到现有数组的末尾,而无需创建新数组或重复复制整个内容。由于这种就场突变,将内存开销最小化,该方法通常利用优化的连续内存块和缓存位置,从而降低了内存访问的成本。
相反,Array.concat不会修改原始数组。取而代之的是,它创建了一个新数组,其中包含串联在一起的原始数组的元素。创建这个新数组涉及为数组的组合大小分配内存,并将两个源数组中的元素复制到这个新分配的空间中。此复制引入了一个开销,通常与两个阵列的大小成比例,使操作的时间复杂性O(m + n),其中m和n是串联阵列的大小。创建一个新数组并复制数据会导致内存使用增加,并且触发垃圾收集的可能性更高,尤其是在非常大的数组中引人注目的。
基准测试始终表明,对于涉及合并或添加大量元素的操作,推动的速度明显要快得多。例如,一个基准表明,对于反复与数千个元素合并阵列,推动的速度大约比Chrome中的Concat快945倍,甚至在Firefox中甚至更快。这种巨大的差异源自Concat创建新数组和重复复制数据的行为,而推动将现有数组更加逐渐地和位置,避免了重复的内存重复重新分配。
但是,这些性能特征可能会根据使用情况而有所不同。如果该目标是两个非常大的预分配阵列的单个串联,则Concat的性能可能相对较好,因为它一次分配一次,并且一次进行副本。在这种情况下,Push的一对一或批处理附加方法可能会引起多个重新分离或内部复制,这可能会降低其理论优势。尽管如此,对于重复合并或添加许多阵列中的许多元素,推动倾向于每增加一个添加的o(1),因为阵列通常会通过几何形式分配内存(超过超过的能力加倍),从而使其总体上高效。
从内存的角度来看,Push的原位突变意味着较少的频率分配,并且可能对内存子系统的压力较小。 Concat方法需要新的分配和复制数据,重新强调内存和缓存,尤其是对于大型数组而言。这种情况会导致conter操作可能超过CPU缓存限制,从而导致由于从高延迟缓存或重复的主内存中获取数据而导致的内存访问时间较慢。推动,避免重新访问数组中的数据,可以更好地利用缓存位置。
应当指出,推动来改变原始数组,而Concat通过返回新数组来保持不变性。这种差异在应用程序设计中很重要,但也会影响性能。与concat的不变串联保证没有副作用,而是支付额外的内存和复制的价格,而通过直接修改源数组来推动速度的不变性。
一些细微差别包括JavaScript引擎可能会根据上下文和复杂性以不同的方式优化这些操作。例如,引擎更积极地优化固定类型或小阵列。同样,Concat的方法签名支持同时附加多个数组和值(超载签名),这需要内部的平坦和复制步骤,以添加开销,而推动直接添加元素而不会扁平。
关于垃圾收集,concat涉及的频繁分配可以增加垃圾收集工作量,因为旧阵列在复制后被丢弃。这可能导致在高分配方案中停顿或性能下降。 Push的种植阵列会减少分配的频率,从而降低了垃圾收集的开销。
总体而言,在推动和concat之间进行选择涉及速度(推动)与不变性/便利性(CONCAT)之间的权衡。对于以性能为优先级的大型阵列的操作,推动通常是可取的方法,因为它更有效的内存处理和较低的开销。随着阵列大小的增加,阵列创建和复制的Concat开销变得非常昂贵。在不变性至关重要的情况下,尽管遭受了惩罚,但仍使用concat。
总而言之,与在大型阵列中的Concat相比,推动通常表现出更好的性能和较低的内存开销,这是由于原地修改,摊销恒定时间附加和减少的复制。 CONCAT遭受其他内存分配和复制成本,因为它每次称为新数组都会产生一个新数组,这会影响所花费的时间和内存使用情况,尤其是在非常大的数组中。当合并许多阵列或处理大量数据集时,这些差异将被放大,根据基准测试,推动的速度比Concat快数百到数千倍。但是,根据用法上下文和引擎优化,这些一般模式可能会有例外,应考虑对代码不可分割性和可维护性的需求。