找回密码
 立即注册

QQ登录

只需一步,快速开始

Ellia.Duan SpreadJS 开发认证

超级版主

70

主题

4716

帖子

7316

积分

超级版主

Rank: 8Rank: 8

积分
7316

SpreadJS 认证SpreadJS 高级认证

Ellia.Duan SpreadJS 开发认证
超级版主   /  发表于:2024-6-21 17:38  /   查看:414  /  回复:0
本帖最后由 Ellia.Duan 于 2024-6-21 17:57 编辑

接上篇https://gcdn.grapecity.com.cn/showtopic-143102-1-1.html
我们简单回顾下上篇文章介绍的状态同步。

当一个单元格的值发生变化后,所有依赖它的单元格都必须重新计算。但GcExcel并不会立即触发这个计算过程,只是把所有依赖它的单元格的状态改变为Dirty,后面GetValue()时才计算,我们把这个过程叫做状态同步。
假设有这样一个表格:A1中存放一个数字10,B1中存放一个公式:=A1+2,C1中存放一个公式:=B1*2。所以当A1的值发生变化后,必须把B1的状态改为Dirty, B1变为Dirty后,又需要把C1的状态变为Dirty。

状态同步过程往往耗费时间较少,所以一般情况下,在SetValue()的时候不需要关闭计算引擎。只有当公式特别多,依赖链特别长的情况下,这个同步过程才会比较耗费时间。
我们接下来介绍下,当公式特别多,依赖链特别长的解决方案。

一、关闭计算引擎
在工作簿中进行大量setValue/setFormula时,可以关闭计算引擎,在设置后,开启计算引擎,大致代码如下:
  1. workbook.setEnableCalculation(false);
  2. setFormulas() // or setValue()
  3. workbook.setEnableCalculation(true);
复制代码
待计算引擎打开后,对公式重计算
  1. workbook.calculate();
复制代码
此方案优点在于,减少状态同步的过程,即减少重复标脏的过程。
当然,在一些场景下,使用上述方案也不是很好,如
1、当在工作簿中已经设置了大量的公式,当新增公式时,使用上述方案,会发现计算引擎关闭后,workbook.calculate()会对所有的工作重计算(包括之前设置好的公式),增加了计算过程,浪费了资源。
2、如下代码,在计算引擎关闭的基础上,getValue会出现结果不正确的问题。
  1. workbook.setEnableCalculation(false);
  2. setFormulas();
  3. getValue()
  4. workbook.setEnableCalculation(true);
复制代码

针对上述两种场景,我们还有延迟标脏的方案。




二、设置延迟标脏
每次setValue/setFormula,都会进行状态同步。如果公式引用较复杂,状态同步的过程较长,此时可以设置延迟标脏,切断状态同步。等到设置好值/公式 后,延迟标脏结束,此时状态同步。
  1. workbook.setDeferUpdateDirtyState(true);
  2. setFormulas(columns);
  3. workbook.setDeferUpdateDirtyState(false);
复制代码



这个方案会减少setValue/setFormula的时间。
我们再来看看,前面提到的两种关闭计算引擎后不适用的两种场景,用延迟标脏方案是否可行?
场景一,在新增值/公式前,设置延迟标脏,设置好之后,延迟标脏结束,此时公式计算,由于脏值只有最新的数据,所以不会公式全计算,不会造成资源浪费,同时还减少了设置值/公式的时间
场景二、在getValue时,获取到脏值,由于此时计算引擎没有关闭,还是会参与公式计算,此时getValue()的值是正确的。


小tips:开启迭代计算,会影响延迟标脏的效果

Question:
如果有一个新的工作簿,开始对一些公式进行设置,然后获取值,此时上述两种性能好一点呢?
答案是一样的。上述两种方案优化的是状态同步的过程,而公式计算的时间是一致的。
即“禁用计算引擎,设置公式,开启计算引擎,重算,获取值”与“禁用迭代计算,设置脏标延迟更新,设置公式,关闭脏标延迟更新,获取值”的整体耗时大致一致。

如果在实际项目中,使用上述任意一种方案后,公式计算耗时仍然较长,可以考虑调整公式结构或者发帖求助联系技术顾问。







0 个回复

您需要登录后才可以回帖 登录 | 立即注册
返回顶部