找回密码
 立即注册

QQ登录

只需一步,快速开始

Clark.Pan 讲师达人认证 悬赏达人认证 SpreadJS 开发认证

超级版主

200

主题

9897

帖子

1万

积分

超级版主

Rank: 8Rank: 8

积分
15523

讲师达人悬赏达人微信认证勋章SpreadJS 认证SpreadJS 高级认证元老葡萄

Clark.Pan 讲师达人认证 悬赏达人认证 SpreadJS 开发认证
超级版主   /  发表于:2023-12-22 17:58  /   查看:624  /  回复:0
本帖最后由 Clark.Pan 于 2023-12-22 18:06 编辑

背景:
       用户需要对Excel文档逐行进行处理,逐行的进行单元格合并以及一些其他设置。在这时候会发现通过循环逐行操作,性能效率非常低下。

解决方案:
       首先定位这个问题是跟单元格合并有关系,GcExcel在单元格合并的底层算法会检测合并区域的属性设置,并排除合并后可能出现的冲突,这个检测就是导致性能低下的原因。

       接下来,我们做几个小实验:setLineStyle
       如下面代码所示,循环对一个1000行15列的单元格进行合并设置,并在循环中对单元格设置边框。值得注意的是为了模拟最坏情况出合并冲突,我在setLineStyle的设置范围上故意写成了1行,这样每两行进行合并时会产生样式设置的冲突。
  1. for(int i = 0; i < 1000; i++) {
  2.   for(int j = 0; j < 15; j++) {
  3.     worksheet.getRange(i*2,j,1,1).getBorders().get(BordersIndex.EdgeTop).setLineStyle(BorderLineStyle.Medium);
  4.     worksheet.getRange(i*2,j,1,1).getBorders().get(BordersIndex.EdgeTop).setColor(Color.GetGreen());
  5.     worksheet.getRange(i*2,j,2,1).merge();
  6.   }
  7. }
复制代码

      运行在个人PC上测试,结果居然花费了33058 ms。这是一个不能令人接受的数字。
      接下来我们换一个试验,还是上述代码,将merge的位置与上面边框设置的位置对调
  1. for(int i = 0; i < 1000; i++) {
  2.   for(int j = 0; j < 15; j++) {
  3.     worksheet.getRange(i*2,j,2,1).merge();
  4.     worksheet.getRange(i*2,j,1,1).getBorders().get(BordersIndex.EdgeTop).setLineStyle(BorderLineStyle.Medium);
  5.     worksheet.getRange(i*2,j,1,1).getBorders().get(BordersIndex.EdgeTop).setColor(Color.GetGreen());
  6.   }
  7. }
复制代码
      然后我们重新跑一下结果,25105 ms 。快了几乎四分之一,虽然时间上还是无法让人接受,从实验可以看出GcExcel内部存在一些策略,根据设置执行顺序的不同会有着不同的性能体验。
       接下来,我们将merge与颜色设置拆开执行,分别运行在两个循环中,如下面代码所示
  1. for(int i = 0; i < 1000; i++) {
  2.   for(int j = 0; j < 15; j++) {
  3.     worksheet.getRange(i*2,j,1,1).getBorders().get(BordersIndex.EdgeTop).setLineStyle(BorderLineStyle.Medium);
  4.     worksheet.getRange(i*2,j,1,1).getBorders().get(BordersIndex.EdgeTop).setColor(Color.GetGreen());
  5.   }
  6. }
  7.                
  8. for(int i = 0; i < 1000; i++) {
  9.   for(int j = 0; j < 15; j++) {
  10.     worksheet.getRange(i*2,j,2,1).merge();        
  11.   }
  12. }
复制代码

      代码中,merge在设置边框之后进行,我这边测试的结果是 15404ms,又快了超过三分之一,但这还不够。
      我们再次修改代码,将循环merge和循环边框设置的位置交换:
  1. for(int i = 0; i < 1000; i++) {
  2.   for(int j = 0; j < 15; j++) {
  3.     worksheet.getRange(i*2,j,2,1).merge();       
  4.   }
  5. }
  6. for(int i = 0; i < 1000; i++) {
  7.   for(int j = 0; j < 15; j++) {
  8.     worksheet.getRange(i*2,j,1,1).getBorders().get(BordersIndex.EdgeTop).setLineStyle(BorderLineStyle.Medium);
  9.     worksheet.getRange(i*2,j,1,1).getBorders().get(BordersIndex.EdgeTop).setColor(Color.GetGreen());
  10.   }
  11. }
复制代码

       运行一下结果,得到一个惊人的数据:2378ms,这次终于体现出了GcExcel的性能。
       有兴趣的小伙伴可以自行测试上述代码,结果可能会跟各自机器配置不同而有差异,但是对比的效果一定是可以明显看出来的。

       综上所述在有合并处理的时候应当优先处理合并行为,另外对于初次使用的用户,可能没有这些知识背景,使用时可能会写出一些有性能问题的Case。这个时候可以联系我们的技术顾问,提供相应的信息,他们有义务为您进行排查。








0 个回复

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