wangguanquan / eec

A fast and lower memory excel write/read tool.一个非POI底层,支持流式处理的高效且超低内存的Excel读写工具
https://github.com/wangguanquan/eec/wiki
Apache License 2.0
226 stars 58 forks source link

fix: 修复并发导出计算列标时cache被错误修改 #375

Open gaecfov opened 5 months ago

gaecfov commented 5 months ago

现在默认缓存200列的下标,超过后使用当时计算的下标

(cherry picked from commit d64b169e391ccc40323980759791ce3a90012949)

wangguanquan commented 5 months ago

EEC从设计初就未考虑支持多线程的情况,如果要支持多线程Styles、SharedString、RowBlock甚至WorksheetWriter都需要重新设计,仅改这一个方法是不能满足多线程的,这个方法如果要改的话只需要将cache删掉即可,将里面c = cache[n]语句改为c = new char[n]即可,不需要缓存200个下标

无论是读还是写EEC都不支持多线程

gaecfov commented 5 months ago

其他的没有细看,当前这个问题是多个用户导出时,写字段式计算的会错误,这个即使不是并发可能会存在问题,cache 也可能被前一个操作处理,这里的 cache 本身应该是不可变的

wangguanquan commented 5 months ago

能否将使用详细描述一下场景以及相关代码示例,我需要复现一下问题

gaecfov commented 5 months ago

能否将使用详细描述一下场景以及相关代码示例,我需要复现一下问题

我重新看了下cache单线程应该没问题,cache 本身的值没什么作用,只是地址占位,具体的值还是当时算的

wangguanquan commented 5 months ago

能否将使用详细描述一下场景以及相关代码示例,我需要复现一下问题

我重新看了下cache单线程应该没问题,cache 本身的值没什么作用,只是地址占位,具体的值还是当时算的

是的,这里定义为cache容易产生歧义,定义为buffer更好理解,它的作用是将数字转为Excel的列号,这里并没有缓存的作用,因为每一行都需要计算完整的列号,比如10万行20列则需要计算10万x20次列号,所以这里为了减少实例化char[]才这么设计的。

缓存列号是可行的,不需要独立缓存只需要将列号缓存到Column中即可,你可以按下面这几个步骤重新修改并提交。

  1. Column新增列号属性realCol
  2. 删除Sheet#cache定义,直接在int2Col方法中new char[]
  3. 修改Sheet#calculateRealColIndex方法和WorksheetWriter#getColumn方法,在设置realColIndex后计算列号并保存到Column
  4. 修改WorksheetWriter#write方法中的int2Col(hc.getRealColIndex()),直接从Column获取列号

另外你可以实测一下是否能提升性能,个人估计影响不大