博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
极速响应Excel数据报表请求的一种方法
阅读量:4597 次
发布时间:2019-06-09

本文共 2887 字,大约阅读时间需要 9 分钟。

摘要

通过缓存和维护Excel Workbook实例,极速响应Excel数据报表请求。

这是一个真实的大数据“云计算”项目中的解决方案,在给定的时间和资源下,只有这种方法是最简单并且是可行的。

XX公司的需求

简单Excel报表:1个sheet。5秒内可以在界面展示。

复杂Excel报表:7个sheet。20秒内可以在界面展示。

并发响应:20个用户

详细介绍

每个sheet中有大量的Excel公式,如 F=E32-[35764%D1]*[DD]/[LD]。

每个单元格的值,需要后台从Mongodb数据库中取出并计算。

Web前端获得后台返回的数据,插入到Excel单元格中,然后Excel自动执行公式,然后将Excel完整地显示到界面中。

时间瓶颈

后台数据获取和数据计算的时间:

1个sheet要3-4s,7个sheet要10到20s。

前台展示剩下的时间:

1个sheet:1到2秒
7个sheet:0到10秒

读取Excel文件需要的时间

1个sheet:1s左右

7个sheet:2s左右

Excel文件构造成POI XSSFWorkbook对象

1个sheet:1s左右

7个sheet:7s左右

最初,我以为是IO有瓶颈,后来发现不是。主要是POI 构造XSSFWorkbook对象,需要花费很长时间。

XSSFWorkbook这可是一个比较大且复杂的数据结构,维护着一个Excel文档的所有信息。

(令人可气的是,测试机Linux服务器性能竟然还不如我的笔记本)

解决方案

考虑到并发请求最多也就是20,而且这只是一个Demo项目,因此“空间换时间”是可行的。

灵感来源:数据库连接池、对象池、缓存等都可以用来提高程序的性能。

最终方案维护一份Workbook资源池。程序启动后,写一个定时器,监控资源池中的对象数量,达到资源下界的时候,就构造一些新的对象放进资源池中。

与数据库连接池等不同的是,Workbook资源池中的每一个XSSFWorkbook对象,只能使用一次。用完后,就必须从资源池中删除。

因为,XSSFWorkbook被使用后,很多状态都变了。

资源池代码结构

public class WorkbookPool {    private static int complexMinSize = TemplatePropertyReader.COMPLEX_MIN_SIZE;    // 复杂报表--最大缓存    private static int complexMaxSize = TemplatePropertyReader.COMPLEX_MAX_SIZE;    public WorkbookPool() {    }    public void init() {      simpleReportTimer();      complexReportTimer();    }   // 定时器任务---创建报表对象        private void simpleReportTimer() {        log.info("Simple Producter Timer Start...");        Timer producterTimer = new Timer();        // 在1秒后执行此任务,每次间隔1秒        producterTimer.schedule(new SimpleProducterTask(), 1000, 1000);    }    private void complexReportTimer() {        log.info("Complex Producter Timer Start...");        Timer complexProducterTimer = new Timer();        // 在1秒后执行此任务,每次间隔1秒        complexProducterTimer.schedule(new ComplexProducterTask(), 1000, 1000);    }// 简单报表--定时器任务    class SimpleProducterTask extends TimerTask {        public void run() {            int simpleSize = simpleVector.size();            if (simpleSize <= simpleMinSize) {                int toBuildSize = simpleMaxSize - simpleSize;                log.info("before : simpleSize=" + simpleSize + ",toBuildSize=" + toBuildSize);                buildSimple(toBuildSize);                log.info("after : simpleSize=" + simpleVector.size());            }        }    }    // 复杂报表--定时器任务    class ComplexProducterTask extends TimerTask {        public void run() {            int complexSize = complexVector.size();            if (complexSize <= complexMinSize) {                int toBuildSize = complexMaxSize - complexSize;                log.info("before: complexSize=" + complexSize + ",toBuildSize=" + toBuildSize);                buildComplex(toBuildSize);                log.info("after: complexSize=" + complexVector.size());            }        }    }}

启示

数据库连接池、对象池、缓存等很多程序设计中的概念,是存在着相似之处的。

学习和借鉴每一个成熟的概念和解决方案,能够产生更多的好方法。

活学活用,灵活解决实际工作中遇到的问题。

拒绝码农,谢绝书呆子。

相关阅读

原文参见: 小雷网(FansUnion.cn)

转载于:https://www.cnblogs.com/qitian1/p/6463517.html

你可能感兴趣的文章
译文 [ROM][多国语言][2015.06.11] Lenovo S750 (MTK6589) - andrea_d86-lenovos750-4.2.2
查看>>
租用游艇问题
查看>>
如何修改SharePoint 2010默认的任务通知邮件的格式?
查看>>
单用户模式下连接被占用定位spid
查看>>
Django JWT
查看>>
云推送注意(MSDN链接)
查看>>
条件编译解决AutoCAD多版本问题
查看>>
java的Integer与int的比较
查看>>
openstack安装文档
查看>>
正在改变世界的硅谷创业趋势
查看>>
No2_3.接口继承多态_Java学习笔记_多态
查看>>
[转] 体内湿气重怎样祛除
查看>>
C#多线程学习(五) 多线程的自动管理(定时器)
查看>>
第三次作业
查看>>
物体坐标to世界坐标
查看>>
上传图片进行预览
查看>>
Git学习笔记(二)
查看>>
[翻译]OAuth入门指南 – 1.概述
查看>>
<context:component-scan/>和<mvc:annotation-driven/>的区别
查看>>
Android 命名规范 (提高代码可以读性)
查看>>