大数据量导出 优化方案多版 第四版

需求

实话说上个版本,问题都已经稳定处理了,但是实话说这并不是一个最好的方法,这只是一个稳定的方法,折中的办法,但是并不是一个最好的办法,目前会有一个最优的解法但是可能没有办法没有时间去研究出一个最优的解了,大家可以看看是不是可以去完善一下,

代码

package cn.chinaunicom.ams.scrappedAssetDetailAll.utils;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class Test0410 {
    // 模拟数据类
    public static class Data {
        private String id;
        private String content;

        public Data(String id, String content) {
            this.id = id;
            this.content = content;
        }

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }
    public static void main(String[] args) {
        // 生成 10 条记录
        List<Data> dataList = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            dataList.add(new Data("ID" + i, "Content " + i));
        }

        // 分组记录,每组 3 条记录
        List<List<Data>> groupedData = new ArrayList<>();
        for (int i = 0; i < dataList.size(); i += 3) {
            groupedData.add(dataList.subList(i, Math.min(i + 3, dataList.size())));
        }

        // 创建一个目录来存储生成的文件
        File outputDir = new File("file/ams/export/2025/04/10");
        if (!outputDir.exists()) {
            outputDir.mkdirs();
        }

        // 文件路径集合
        List<String> fileCollection = new ArrayList<>();

        // 创建线程列表
        List<Thread> threads = new ArrayList<>();

//        // 创建线程并启动
//        for (int i = 0; i < groupedData.size(); i++) {
//            final int index = i;
//            Thread thread = new Thread(() -> {
//                List<Data> records = groupedData.get(index);
//                String fileName = "output_" + (index + 1) + ".xlsx";
//                String filePath = outputDir.getAbsolutePath() + File.separator + fileName;
//
//                // 写入文件
//                writeDataToExcel(records, filePath);
//                synchronized (fileCollection) {
//                    fileCollection.add(filePath);
//                }
//                System.out.println("Thread " + Thread.currentThread().getName() + " wrote " + records.size() + " records to " + filePath);
//            });
//            threads.add(thread);
//            thread.start();
//        }



        Thread thread1 = new Thread(() -> {
            List<Data> records = groupedData.get(0);
            String fileName = "output_" + (0 + 1) + ".xlsx";
            String filePath = outputDir.getAbsolutePath() + File.separator + fileName;

            // 写入文件
            writeDataToExcel(records, filePath);
            synchronized (fileCollection) {
                fileCollection.add(filePath);
            }
            System.out.println("Thread " + Thread.currentThread().getName() + " wrote " + records.size() + " records to " + filePath);
        });
        threads.add(thread1);
        thread1.start();



        Thread thread2 = new Thread(() -> {
            List<Data> records = groupedData.get(1);
            String fileName = "output_" + (1 + 1) + ".xlsx";
            String filePath = outputDir.getAbsolutePath() + File.separator + fileName;

            // 写入文件
            writeDataToExcel(records, filePath);
            synchronized (fileCollection) {
                fileCollection.add(filePath);
            }
            System.out.println("Thread " + Thread.currentThread().getName() + " wrote " + records.size() + " records to " + filePath);
        });
        threads.add(thread2);
        thread2.start();



        Thread thread3 = new Thread(() -> {
            List<Data> records = groupedData.get(2);
            String fileName = "output_" + (2 + 1) + ".xlsx";
            String filePath = outputDir.getAbsolutePath() + File.separator + fileName;

            // 写入文件
            writeDataToExcel(records, filePath);
            synchronized (fileCollection) {
                fileCollection.add(filePath);
            }
            System.out.println("Thread " + Thread.currentThread().getName() + " wrote " + records.size() + " records to " + filePath);


             records = groupedData.get(3);
             fileName = "output_" + (3 + 1) + ".xlsx";
             filePath = outputDir.getAbsolutePath() + File.separator + fileName;

            // 写入文件
            writeDataToExcel(records, filePath);
            synchronized (fileCollection) {
                fileCollection.add(filePath);
            }
            System.out.println("Thread " + Thread.currentThread().getName() + " wrote " + records.size() + " records to " + filePath);
        });
        threads.add(thread3);
        thread3.start();


        // 等待所有线程完成
        for (Thread thread : threads) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


        // 输出文件集合
        System.out.println("Generated files:");
        fileCollection.forEach(System.out::println);
    }
    // 使用 EasyExcel 写入数据
    private static void writeDataToExcel(List<Data> data, String fileName) {
        EasyExcel.write(fileName, Data.class)
                .sheet("Sheet1")
                .doWrite(data);
    }
}

其实这套方案的意义就是在保障,外面一个线程池,里面多个线程,我们去手动调度,这样的话可以保证,系统不会死,并且更好的提高效率,外面的线程池是为了避免系统太多的性能放在导出上面,里面的多个线程可以提高写入的性能,但是这套逻辑还是有问题的,因为我们的需求就是,会导出多个省份的数据,不同的省份数据量不同,所以说这只是一个demo,还带完善。

更优解

其实,我觉得比较好的方式就是设立一个导出服务器,代码直接滚回最初的版本,连第一版都不用了,直接使用一个独立的导出服务器,当时这套方案的底层就是加服务器,性能不行加服务器就好了,但是没得办法加不了,独立服务器绝对是最优的解。
或者是说记录下来导出的文件, 等待晚上或者服务器有空闲的时候进行执行,上述的第一个办法就是拆分服务器性能,第二个方法就是拆分出服务器的时间,其实说白了,io就是消耗性能,你在牛也是需要消耗性能的,就是要加性能或者拆开时间去使用的,或者是说直接去使用服务器的时间片,更加底层的导出IO处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

又是重名了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值