Java ApachePOI-缓存工作簿是重用的最佳方式吗?

Java ApachePOI-缓存工作簿是重用的最佳方式吗?,java,apache-poi,Java,Apache Poi,我们在生产中使用ApachePOI已有几年了,并取得了良好的效果。目前在版本3.11上。我们只使用HSSF(根据我们的测试,它比XSSF快,并且我们可以在没有XLSX的情况下生活。) 我们目前在内存中保留了一个“同步工作簿运行程序”的缓存映射,大约70个。将每个XLS看作一个产品,映射键告诉我们使用哪一个。我们在启动时加载缓存,这样就不会实时读取文件 我们的同步跑步者大致如下: public class PoiProcessorSynchronized { private Workbook

我们在生产中使用ApachePOI已有几年了,并取得了良好的效果。目前在版本3.11上。我们只使用HSSF(根据我们的测试,它比XSSF快,并且我们可以在没有XLSX的情况下生活。)

我们目前在内存中保留了一个“同步工作簿运行程序”的缓存映射,大约70个。将每个XLS看作一个产品,映射键告诉我们使用哪一个。我们在启动时加载缓存,这样就不会实时读取文件

我们的同步跑步者大致如下:

public class PoiProcessorSynchronized {
  private Workbook workbook;
  public synchronized Map<String, Object> process(Request request) {
    engine.process(workbook, request); //request has input/output params
  }
}
公共类POI处理器已同步{
私人工作手册;
公共同步映射进程(请求){
engine.process(工作簿,请求);//请求具有输入/输出参数
}
}
这使得性能非常好(在过去24小时内,平均每秒112ms的请求量为27k),有些工作表速度慢,有些工作表速度快。我们在处理之间手动重置输入到工作表中,以确保工作表在使用之间是干净的

保持工作表的处理同步是为了防止计算错误。我们最初确实看到一些计算错误,但没有控制对表格的访问。自从我们这样做以来,它一直是坚实的

我关心的一些问题:

  • 每个XLS在每个服务器上一次只能处理一个请求。我想我们可以通过使用某种处理器池来解决这个问题
  • 工作簿的内存相对较大。如果我们继续向缓存中添加XLS,我们必须添加越来越多的内存
  • 还有其他人想做类似的事情吗?这种方法目前正在发挥作用,但感觉应该有更好的方法

    我们是否可能正在缓存工作簿中的其他内容?还是连载


    是否有人在不同步工作簿的情况下成功地通过工作簿处理了大量数据?如果是,如何实现?

    这个问题的答案完全取决于POI本身是否以完全线程安全的方式实现

    鉴于POI站点上的文档或FAQ中没有提到并发性和线程安全性,您必须假设它不是线程安全的

    快速浏览会发现没有同步关键字,并且使用了简单的未同步集合。。。所以不,它不是线程安全的


    因此,您的同步方法可能是您所能做到的最好的方法。

    在库级别,ApachePOI是线程安全的。在工作簿级别(+sheet/row/cell/etc级别),Apache POI不是线程安全的。给定工作簿一次只能由一个线程处理。如果有多个线程并行工作,那么它们必须有自己的工作簿来处理。不支持两个线程在同一工作簿上工作(包括在同一工作簿中的不同工作表上工作)

    总的来说,加载.xls文件相当快。使用a可稍微降低内存并稍微加快加载速度。看。确保您使用的是最新版本的ApachePOI

    对于您的特定情况,对最流行的工作簿进行某种缓存可能会很好。也许只适用于较大的流行工作簿,小工作簿总是按需加载


    否则,尝试一些评测,看看是否有地方POI对某些文件做了太多的工作。然后,性能改进总是受到项目的欢迎

    ApachePOI总体上是线程安全的,但工作簿及其内容不是线程安全的。您可以让不同的线程都非常愉快地处理它们自己的工作簿,但您必须只有一个线程处理单个给定的打开线程workbook@Gagravarr我们完全可以并且确实可以通过上述方式实现这一目标。从您的角度来看,工作簿是正确的缓存对象,尽管@javatestcase我们也在做同样的事情(使用XSSF而不是HSSF)。我们正在使用org.apache.commons.pool.impl.GenericKeyedObjectPool进行池化。@Kai谢谢,我将尝试实现它。