【发布时间】:2015-12-31 23:57:36
【问题描述】:
几年来,我们一直在生产环境中使用 Apache POI,并取得了不错的效果。当前版本为 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
}
}
这使得性能非常好(过去 24 小时平均 112 毫秒的 27k 请求)一些工作表很慢,一些工作表很快。我们在处理之间手动重置输入到工作表中,以确保工作表在两次使用之间保持清洁。
保持工作表处理同步是为了防止计算错误。我们最初确实看到了一些计算错误,而没有控制对工作表的访问。自从我们这样做以来,它一直很稳固。
我关心的一些问题:
- 对于每台服务器,每个 XLS 一次只能处理一个请求。我想我们可以通过使用某种处理器池来解决这个问题
- 工作簿的内存相对较大。如果我们继续将 XLS 添加到缓存中,我们必须添加越来越多的内存。
还有其他人尝试做类似的事情吗?该方法目前有效,但感觉应该有更好的方法。
我们是否可以缓存其他工作簿的内容?还是序列化一些东西?
有没有人通过工作簿成功处理大量数据而不同步它们?如果有怎么办?
【问题讨论】:
-
Apache POI 总体上是线程安全的,但工作簿及其内容不是。您可以让不同的线程非常愉快地在自己的工作簿上工作,但您必须只有一个线程处理一个给定的打开工作簿
-
@Gagravarr 我们绝对可以并且确实可以通过上述方式实现这一目标。从您的角度来看,Workbook 是正确的缓存对象吗?
-
@javatestcase 我们做的基本相同(使用 XSSF 而不是 HSSF)。我们正在使用 org.apache.commons.pool.impl.GenericKeyedObjectPool 进行池化。
-
@Kai 谢谢,我将尝试实现它。
标签: java apache-poi