EasyExcel 带格式多线程导出百万数据(实测好用)

大家好,我是宝哥!

前言

以下为结合实际情况作的方案设计,导出阈值以及单sheet页条数都可以根据实际情况调整

大佬可直接跳过新手教程,直接查看文末代码

1. 背景说明

针对明细报表,用户会选择针对当前明细数据进行导出,便于本地或者线下进行处理或者计算等需求。不过一般在这种大数据量的导出任务下,会引发以下问题:

  • 响应时间较慢;

  • 内存资源占用过大,基本上一个大数据量的导出会消耗可视化服务的所有资源,引起内存回收,其它接口无响应;

考虑到单个excel文件过大,采用压缩文件流zip的方式,一个excel只有一个页签,一个页签最多十万条数据,所以少于十万条数据,会导出excel文件,而非zip压缩文件。

另外,这里导出功能的速率不能单以数据条数为量级进行衡量,平常一般一万条数据就是1M字节。较为准确的公式如下(借此就可以评估出很多数据导出的文件大小):

文件大小1M字节 = 字段列数15个 * 数据条数一万条

2. 方案概述

(1)大数据量导出问题主要是以下三个地方:

  • 资源占用

  • 内存(也是资源的一个,单独说明)

  • 响应时间

针对以上三个问题,大方向考虑的是多线程结合数据流写入的方式。多线程:使用空间换时间,主要是加快接口响应时间,但是这里线程数不宜过多,一味加快响应时间提升线程数,资源占用会非常严重,故会考虑线程池,线程池的线程数为10;数据流:数据的IO-读取/写入等操作一般都是通过“数据包”的方式,即将结果数据作为一个整体,这样如果数据量多的话,会非常占用内存,所以采用数据流的方式,而且导出的时候会进行格式设置(单元格合并、背景色、字体样式等),一直使用的是Alibaba EasyExcel组件,并且Alibaba EasyExcel组件支持数据流的方式读取/写入数据。

(2)将写入导出Excel等功能单独分开成一个微服务:

注意:如果单个服务分配的资源足够的话,可以不用将导出功能与原应用服务拆开,这里可以省略

  • 抢占资源

  • 由于导出功能内存溢出,如果不做分离独立,整个应用服务也会宕机

(3)注意:

  • 多线程下,同一页签的写入不可同步,即Alibaba EasyExcel组件的文件写入流SheetWriter是异步的;

  • 多线程下,每个线程所用的文件写入SheetWriter是一个复制,依旧会占用大量内存;

  • 微服务拆分时,数据读取和文件写入是在一个线程下的,所以新的微服务也要实现一套数据读取逻辑;

  • 压缩文件使用压缩文件流,ZipOutputStream,不需要暂存本地;

(4)方案设计:

a7f8ca4934d561d4bc48841fcc45b7ec.png

标注说明

1) 阈值可以进行设置,考虑到业务场景以及资源使用,这里阈值数据量为100w条,超过一百万会导出空表(而非导出一百万数据)

2) 导出进行多线程,启用最多十个多线程(默认最多一百万条数据,一个sheet页十万条数据),每个线程会进行两个动作,查询数据以及数据写入操作,(如果数据量较少,依旧是适用的)

3) 说明图,以86万数据为例,也就是说会启用九个文件写入线程,一个文件写入线程生成一个excel导出文件;

9f7d7f9aa8df0e90507af1cb77a0a256.png

4) 线程池为队列线程,即后来的线程进入排队等待,队列长度(线程池大小)为10;

5) 每个文件写入线程会生成最多十个sheet(默认一个sheet页十万数据)写入线程(最后一个文件写入线程可能会少于十个)。

571a2bdf5ad543c07ce18e8bd07fd860.png

(5)maven依赖:

<!-- easyexcel -->
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.1.7</version>
</dependency>

3. 详细设计

(1)文件写入多线程,按每个文件十万条数据进行导出,每个文件写入线程生成一个excel文件(单页签);

  • ROW_SIZE:一次查询的数据量,此处设置为10000条

  • ROW_PAGE:一个页签多少次查询,此处设置为10次;

private static Interger ROW_SIZE = 10000;
private static interger ROW_PAGE = 10;
/**  
* divide into sheets with 10W data per sheet  
* */
int sheetCount = (rowCount/ (ROW_SIZE*ROW_PAGE))+1;
for(int i=0;i<sheetCount;i++){threadExecutor.submit(()->{sheetWrite()});
}

(2)sheet写入多线程,最后一个文件写入线程的最后一个sheet写入线程可能不足1W条数据;

// 单sheet页写入数
int sheetThreadCount = rowCount - (i+1)*(ROW_SIZE*ROW_PAGE) > 0 ? ROW_PAGE : (rowCount - i*(ROW_SIZE*ROW_PAGE))/ROW_SIZE+1;
CountDownLatch threadSignal = new CountDownLatch(sheetThreadCount);
for(int j=0;j<sheetThreadCount;j++) {threadExecutor.submit(()->{excelWriter()});
}
threadSignal.await();

(3)异步写入sheet文件,不同的文件写入线程写入不同的文件,所以只需要保证同一个文件写入线程下不同sheet写入线程的excelWriter异步即可;

// 获取数据
// todo
// 数据格式处理
Synchronized(excelWriter){WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo, "第" + (sheetNo+1) + "页数据");excelWriter.write(lists, writeSheet);
}

(4)压缩文件,将多个excel压缩成一个zip,最后上传至fast dfs,返回前端下载地址,使用hutool封装的ZipUtil方法;

package cn.hutool.core.util;
String[] paths = new String[10]; 
FileInputStream[] ins = new FileInputStream[10];
ZipUtil.zip(OutputStream out, String[] paths, InputStream[] ins);
byte[] bytes = outputStream.toByteArray();
// 上传文件到FastDFS  返回上传路径
String path = fastWrapper.uploadFile(bytes, bytes.length, "zip");
return path + "?filename=" + fileName;

4. 缓存

每次请求是生成一个文件并上传至FastDFS服务器上,然后将下载路径返回给前端,有时多个用户频繁下载同一个文件(或者用户短时间内点击同一个下载任务)。针对以上情况,考虑采用缓存,将第一次的数据缓存下来。

① 请求参数较多,需要根据参数判断是否为同一个下载文件请求;

  • 数据集ID

  • 过滤器

  • 数据量

  • 数据集字段(先根据ID排序,再进行拼接)

② 设置过期时间(30分钟),不考虑数据一致性的问题(即数据源数据更改后,再更新缓存)。仅仅是做初步工作,即短时间内,只要符合条件①且时间未过期,就采用同一份数据;

③ 当请求下载的为同一份文件时,只是文件名不同时,依旧采用同一份缓存数据;

注:针对于数据一致性的问题,不对单个数据的内容变更进行考虑,原因是大数据量下,数据是否有变更的判断较为复杂,不现实。这里只判断在相同的请求条件下的总条数。

5. 可行性验证

(1)单个文件写入下,176个字段,14140条数据,excel大小15M,响应时间为14.66s(未报错,未触发异常)

b6780f8578352811ce7df32073f1e06d.png

(2)单个文件写入下,14个字段,98万数据,excel大小为96M,响应时间为42.41s(未报错,未触发异常)

205079d6d9de85a4721b06196867cd16.png

(3)拆分微服务下,14个字段,98万数据,zip大小为104M,平均响应时间为27.34s(未报错,未触发异常)

255a121c21055716c0f5dfa35a6f4702.png

6. 代码

文件导出核心代码

TableExport.java

public String exportTable(ExportTable exportTable) throws Exception {StringBuffer path = new StringBuffer();ByteArrayOutputStream outputStream = new ByteArrayOutputStream();StringBuffer sign = new StringBuffer ();//redis keysign.append(exportTable.getId());try {// 用来记录需要为 行 列设置样式Map<String, Map<Integer, List<Map<Integer, ExportTable.ExportColumn.Font>>>> map = new HashMap<>();sign.append("#").append(String.join(",", fields.stream().map(e-> e.isShow()?"true":"false").collect(Collectors.toList())));setFontStyle(0, 0, exportTable.getFields(), map);// 获取表头长度int headRow = head.stream().max(Comparator.comparingInt(List::size)).get().size();// 数据量超过十万 则不带样式// 只处理表头:表头合并 表头隐藏 表头冻结if(rowCount*fields.size() > ROW_SIZE*6.4){map.put("cellStyle", null);}sign.append("#").append(exportTable.getStyle());// 数据量超过百万或者数据为空,只返回有表头得单元格if(rowCount==0 || rowCount*fields.size() >= ROW_SIZE*1500){EasyExcel.write(outputStream)// 这里放入动态头.head(head).sheet("数据")// 传入表头样式.registerWriteHandler(EasyExcelUtils.getStyleStrategy())// 当然这里数据也可以用 List<List<String>> 去传入.doWrite(new LinkedList<>());byte[] bytes = outputStream.toByteArray();// 上传文件到FastDFS  返回上传路径return fastWrapper.uploadFile(bytes, bytes.length, "xlsx") + "?filename=" + fileName + ".xlsx";}sign.append("#").append(rowCount);String fieldSign = fields.stream().sorted(Comparator.comparing(ExportTable.ExportColumn::getId)).map(e->e.getId()).collect(Collectors.joining(","));sign.append("#").append(fieldSign);/*** 相同的下载文件请求 直接返回* the redis combines with datasetId - filter - size of data - fields*/if (redisClientImpl.hasKey(sign.toString())){return redisClientImpl.get(sign.toString()).toString();}/*** 分sheet页* divide into sheets with 10M data per sheet*/int sheetCount = (rowCount/ (ROW_SIZE*ROW_PAGE))+1;String[] paths = new String[sheetCount];ByteArrayInputStream[] ins = new ByteArrayInputStream[sheetCount];CountDownLatch threadSignal = new CountDownLatch(sheetCount);for(int i=0;i<sheetCount;i++) {int finalI = i;String finalTable = table;Datasource finalDs = ds;String finalOrder = order;int finalRowCount = rowCount;threadExecutor.submit(()->{// excel文件流ByteArrayOutputStream singleOutputStream = new ByteArrayOutputStream();ExcelWriter excelWriter = EasyExcel.write(singleOutputStream).build();// 单sheet页写入数int sheetThreadCount = finalI == (sheetCount-1) ? (finalRowCount - finalI *(ROW_SIZE*ROW_PAGE))/ROW_SIZE+1 : ROW_PAGE;CountDownLatch sheetThreadSignal = new CountDownLatch(sheetThreadCount);for(int j=0;j<sheetThreadCount;j++) {int page = finalI *ROW_PAGE + j + 1;// 最后一页数据int pageSize = j==(sheetThreadCount-1)&& finalI ==(sheetCount-1) ? finalRowCount %ROW_SIZE : ROW_SIZE;threadExecutor.submit(()->{try {writeExcel(dataSetTableRequest, datasetTable, finalTable, qp,datasetTableFields, exportTable, page, pageSize, finalDs, datasourceProvider,fieldArray, fields, head, map, headRow, excelWriter, mergeIndex, finalOrder);sheetThreadSignal.countDown();} catch (Exception e) {e.printStackTrace();}});}try {sheetThreadSignal.await();} catch (InterruptedException e) {e.printStackTrace();}// 关闭写入流excelWriter.finish();paths[finalI] = (finalI +1) + "-" + fileName + ".xlsx";// 单文件if (sheetCount == 1){// xlsx// 将sign存入redis并设置过期时间}threadSignal.countDown();});}threadSignal.await();if (sheetCount != 1){ZipUtil.zip(outputStream, paths, ins);byte[] bytes = outputStream.toByteArray();// 上传文件到FastDFS  返回上传路径path.append(fastWrapper.uploadFile(bytes, bytes.length, "zip")).append("?filename=").append(fileName).append(".zip");// 将sign存入redis并设置过期时间redisClientImpl.set(sign.toString(), path.toString(), SYS_REDIS_EXPIRE_TIME);}} catch (Exception e) {e.printStackTrace();}return path.toString();}private void writeExcel(ExcelWriter excelWriter){//数据查询// todosynchronized (excelWriter) {WriteSheet writeSheet = EasyExcel.writerSheet(0, "第" + 1 + "页数据")// 这里放入动态头.head(head)//传入样式.registerWriteHandler(EasyExcelUtils.getStyleStrategy()).registerWriteHandler(new CellColorSheetWriteHandler(map, headRow)).registerWriteHandler(new MergeStrategy(lists.size(), mergeIndex))// 当然这里数据也可以用 List<List<String>> 去传入.build();excelWriter.write(lists, writeSheet);}}

Excel导出的文件流样式处理类。

CellColorSheetWriteHandler.java

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.util.StyleUtil;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFColor;
import org.apache.poi.xssf.usermodel.XSSFFont;import java.awt.Color;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;/*** @Author 菜鸟* @description 拦截处理单元格创建*/
public class CellColorSheetWriteHandler implements CellWriteHandler
{/*** 多行表头行号*/private int headRow;/*** 字体*/private ExportTable.ExportColumn.Font columnFont = new ExportTable.ExportColumn.Font();private static volatile XSSFCellStyle cellStyle = null;public static XSSFCellStyle getCellStyle(Workbook workbook, WriteCellStyle contentWriteCellStyle) {if(cellStyle == null) {synchronized (XSSFCellStyle.class) {if(cellStyle == null) {cellStyle =(XSSFCellStyle) StyleUtil.buildHeadCellStyle(workbook, contentWriteCellStyle);}}}return cellStyle;}/*** 字体* Map<Integer, ExportTable.ExportColumn.Font> 当前列的字段样式* Map<Integer, List<Map<...>>> 当前行包含那几列需要设置样式* String head:表头;* String cell:内容;*/private Map<String, Map<Integer, List<Map<Integer, ExportTable.ExportColumn.Font>>>> map;/*** 有参构造*/public CellColorSheetWriteHandler(Map<String, Map<Integer, List<Map<Integer, ExportTable.ExportColumn.Font>>>> map, int headRow) {this.map = map;this.headRow = headRow;}/*** 在单元上的所有操作完成后调用*/@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {// 当前行的第column列int column = cell.getColumnIndex();// 当前第row行int row = cell.getRowIndex();AtomicInteger fixNum = new AtomicInteger();// 处理行,表头if (headRow > row && map.containsKey("head")){Map<Integer, List<Map<Integer, ExportTable.ExportColumn.Font>>> fonts = map.get("head");fonts.get(row).forEach(e->{e.entrySet().forEach(ele -> {// 获取冻结字段if (null != ele.getValue().getFixed() && !StringUtils.isEmpty(ele.getValue().getFixed())) {fixNum.getAndIncrement();}// 字段隐藏if(!ele.getValue().isShow()){writeSheetHolder.getSheet().setColumnHidden(ele.getKey(), true);}});});if (fixNum.get() > 0 && row == 0) {writeSheetHolder.getSheet().createFreezePane(fixNum.get(), headRow, fixNum.get(), headRow);}else{writeSheetHolder.getSheet().createFreezePane(0, headRow, 0, headRow);}setStyle(fonts, row, column, cell, writeSheetHolder, head);}// 处理内容if (headRow <= row && map.containsKey("cell") && !map.containsKey("cellStyle")) {Map<Integer, List<Map<Integer, ExportTable.ExportColumn.Font>>> fonts = map.get("cell");setStyle(fonts, -1, column, cell, writeSheetHolder, head);}}private void setStyle(Map<Integer, List<Map<Integer, ExportTable.ExportColumn.Font>>> fonts, int row, int column, Cell cell, WriteSheetHolder writeSheetHolder, Head head){fonts.get(row).forEach(e->{if (e.containsKey(column)){// 根据单元格获取workbookWorkbook workbook = cell.getSheet().getWorkbook();//设置列宽if(null != e.get(column).getWidth() && !e.get(column).getWidth().isEmpty()) {writeSheetHolder.getSheet().setColumnWidth(head.getColumnIndex(), Integer.parseInt(e.get(column).getWidth()) * 20);}else{writeSheetHolder.getSheet().setColumnWidth(head.getColumnIndex(),2000);}// 单元格策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 设置垂直居中为居中对齐contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 设置左右对齐方式if(null != e.get(column).getAlign() && !e.get(column).getAlign().isEmpty()) {contentWriteCellStyle.setHorizontalAlignment(getHorizontalAlignment(e.get(column).getAlign()));}else{contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);}if (!e.get(column).equal(columnFont) || column == 0){/*** Prevent the creation of a large number of objects* Defects of the EasyExcel tool(巨坑,简直脱发神器)*/cellStyle = (XSSFCellStyle) StyleUtil.buildHeadCellStyle(workbook, contentWriteCellStyle);// 设置单元格背景颜色if(null != e.get(column).getBackground() && !e.get(column).getBackground().isEmpty()) {cellStyle.setFillForegroundColor(new XSSFColor(hex2Color(e.get(column).getBackground())));}else{if(cell.getRowIndex() >= headRow)cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());}// 创建字体实例Font font = workbook.createFont();// 设置字体是否加粗if(null != e.get(column).getFontWeight() && !e.get(column).getFontWeight().isEmpty())font.setBold(getBold(e.get(column).getFontWeight()));// 设置字体和大小if(null != e.get(column).getFontFamily() && !e.get(column).getFontFamily().isEmpty())font.setFontName(e.get(column).getFontFamily());if(0 != e.get(column).getFontSize())font.setFontHeightInPoints((short) e.get(column).getFontSize());XSSFFont xssfFont = (XSSFFont)font;//设置字体颜色if(null != e.get(column).getColor() && !e.get(column).getColor().isEmpty())xssfFont.setColor(new XSSFColor(hex2Color(e.get(column).getColor())));cellStyle.setFont(xssfFont);// 记录上一个样式columnFont = e.get(column);}// 设置当前行第column列的样式cell.getRow().getCell(column).setCellStyle(cellStyle);// 设置行高cell.getRow().setHeight((short) 400);}});}
}

Excel导出的默认样式设置类。

EasyExcelUtils.java

public static HorizontalCellStyleStrategy getStyleStrategy(){// 头的策略WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 背景设置为灰色headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());WriteFont headWriteFont = new WriteFont();headWriteFont.setFontHeightInPoints((short)12);// 字体样式headWriteFont.setFontName("Frozen");// 字体颜色headWriteFont.setColor(IndexedColors.BLACK1.getIndex());headWriteCellStyle.setWriteFont(headWriteFont);// 自动换行headWriteCellStyle.setWrapped(false);// 水平对齐方式(修改默认对齐方式——4.14 版本1.3.2)headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);// 垂直对齐方式headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 内容的策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定//        contentWriteCellStyle.setFillPatternType(FillPatternType.SQUARES);// 背景白色contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());// 水平对齐方式(修改默认对齐方式——4.14 版本1.3.2)contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);WriteFont contentWriteFont = new WriteFont();// 字体大小contentWriteFont.setFontHeightInPoints((short)12);// 字体样式contentWriteFont.setFontName("Calibri");contentWriteCellStyle.setWriteFont(contentWriteFont);// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现return new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);}

Excel导出合并单元格处理类。

MergeStrategy.class

import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.merge.AbstractMergeStrategy;
import org.apache.commons.collections.map.HashedMap;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;import java.util.*;/*** @Author 菜鸡* @description 合并单元格策略*/
public class MergeStrategy extends AbstractMergeStrategy
{/*** 合并的列编号,从0开始* 指定的index或自己按字段顺序数*/private Set<Integer> mergeCellIndex = new HashSet<>();/*** 数据集大小,用于区别结束行位置*/private Integer maxRow = 0;// 禁止无参声明private MergeStrategy() {}public MergeStrategy(Integer maxRow, Set<Integer> mergeCellIndex) {this.mergeCellIndex = mergeCellIndex;this.maxRow = maxRow;}private Map<Integer, MergeRange> lastRow = new HashedMap();@Overrideprotected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {int currentCellIndex = cell.getColumnIndex();// 判断该行是否需要合并if (mergeCellIndex.contains(currentCellIndex)) {String currentCellValue = cell.getStringCellValue();int currentRowIndex = cell.getRowIndex();if (!lastRow.containsKey(currentCellIndex)) {// 记录首行起始位置lastRow.put(currentCellIndex, new MergeRange(currentCellValue, currentRowIndex, currentRowIndex, currentCellIndex, currentCellIndex));return;}//有上行这列的值了,拿来对比.MergeRange mergeRange = lastRow.get(currentCellIndex);if (!(mergeRange.lastValue != null && mergeRange.lastValue.equals(currentCellValue))) {// 结束的位置触发下合并.// 同行同列不能合并,会抛异常if (mergeRange.startRow != mergeRange.endRow || mergeRange.startCell != mergeRange.endCell) {sheet.addMergedRegionUnsafe(new CellRangeAddress(mergeRange.startRow, mergeRange.endRow, mergeRange.startCell, mergeRange.endCell));}// 更新当前列起始位置lastRow.put(currentCellIndex, new MergeRange(currentCellValue, currentRowIndex, currentRowIndex, currentCellIndex, currentCellIndex));}// 合并行 + 1mergeRange.endRow += 1;// 结束的位置触发下最后一次没完成的合并if (relativeRowIndex.equals(maxRow - 1)) {MergeRange lastMergeRange = lastRow.get(currentCellIndex);// 同行同列不能合并,会抛异常if (lastMergeRange.startRow != lastMergeRange.endRow || lastMergeRange.startCell != lastMergeRange.endCell) {sheet.addMergedRegionUnsafe(new CellRangeAddress(lastMergeRange.startRow, lastMergeRange.endRow, lastMergeRange.startCell, lastMergeRange.endCell));}}}}
}class MergeRange {public int startRow;public int endRow;public int startCell;public int endCell;public String lastValue;public MergeRange(String lastValue, int startRow, int endRow, int startCell, int endCell) {this.startRow = startRow;this.endRow = endRow;this.startCell = startCell;this.endCell = endCell;this.lastValue = lastValue;}
}

来源:blog.csdn.net/qq_40921561/article/details/126764038

 
往期推荐:
用上这几个开源管理系统做项目,领导看了直呼专业!13 款炫酷的 MySQL 可视化管理工具!好用到爆!!订单超时未支付自动取消5种实现方案ES+Redis+MySQL,这个高可用架构设计太顶了!6个顶级SpringCloud微服务开源项目,企业开发必备!Spring Boot 使用 ChatGPT API 开发一个聊天机器人SpringBoot + Sharding JDBC,一文搞定分库分表、读写分离

b5c9cd6ffac40b1672fe3fae0a31de70.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/15626.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面对当下各种不确定性,如何面对,每天很忙碌,不慌

&#xff08;点击即可收听&#xff09; 疫情时期,都难,疫情之后,发现还更难 随着互联网的热度的下降,各大小公司纷纷勒紧裤腰带,受打击最大的无疑是底层打工人 每天一打开手机,会发现,一些大厂裁员信息霸榜头条,年龄也是一道坎 刚刚看到一个大v发的&#xff1a; 一个原先是跨国…

剑桥华人团队搞出多模态医学大模型!单个消费级显卡就能部署,借鉴斯坦福「羊驼」而来...

衡宇 发自 凹非寺量子位 | 公众号 QbitAI ChatGPT、AutoGPT能干那么些事&#xff0c;好想知道大模型啥时候才能看病&#xff0c;救我本人狗命&#xff1f; 带视觉的多模态医学基础大模型&#xff0c;它来啦&#xff5e; 名为Visual Med-Alpaca&#xff0c;官宣即开源。 这个专为…

技术动态 | 也看大模型在事理图谱中的有趣表现:从概率链式因果搜索到因果抽取再到指令驱动的图谱构建评测...

转载公众号 | 老刘说NLP 事理图谱是过去一年来比较火的一个方向&#xff0c;其靠着主打推理预测这一特点&#xff0c;通过构建以事件为核心&#xff0c;事件之间因果等关系&#xff0c;形成传导推理链&#xff0c;一度被认为大有可为。 但目前大模型席卷之下&#xff0c;事理图…

PPO算法基本原理及流程图(KL penalty和Clip两种方法)

PPO算法基本原理 PPO&#xff08;Proximal Policy Optimization&#xff09;近端策略优化算法&#xff0c;是一种基于策略&#xff08;policy-based&#xff09;的强化学习算法&#xff0c;是一种off-policy算法。 详细的数学推导过程、为什么是off-policy算法、advantage函数…

达摩院用128张GPU烧出“中文版GPT-3”,我试了下,这文风不是开往幼儿园的车…...

杨净 子豪 发自 凹非寺 量子位 报道 | 公众号 QbitAI 首先&#xff0c;请先看一段“正经”的文字&#xff1a; 他笑意中的那份温柔&#xff0c;只想给她好好珍藏&#xff0c;即便这一切不会发生&#xff0c;至少在他的世界里&#xff0c;她是无忧无虑的快乐的。就连他对她的关心…

洞察ChatGPT巨大价值,云知声积极推动行业版ChatGPT落地

近日&#xff0c;ChatGPT的风越刮越猛&#xff0c;不由让人好奇&#xff0c;作为“能说会道”的ChatGPT&#xff0c;能够运用在专业性更高的行业&#xff1f;遗憾的是&#xff0c;从目前ChatGPT给出的答案来看&#xff0c;它距离运用在医疗等专业领域尚有距离。对此&#xff0c…

ChatGPT提示词工程师教程-迭代

不要奢求“一针见血”&#xff0c;要不断打磨&#xff0c;形成良好的提示词迭代流程。多维度&#xff0c;多样本。就像用搜索引擎一样&#xff0c;第一次搜索没有得到想要的结果&#xff0c;就要对搜索的关键词进行修。参考“指南”&#xff0c;想想是否提示词不够清晰&#xf…

ChatGPT 提示的艺术 —— 如何编写清晰有效提示指南

ChatGPT 提示的作用 正如我们之前提到的那样&#xff0c;ChatGPT 对话中使用的提示的质量可以显著影响对话的成功。定义清晰的提示可以确保对话保持在正确的轨道上&#xff0c;并涵盖用户感兴趣的主题&#xff0c;从而产生更引人入胜和信息丰富的体验。 那么什么样的 ChatGPT…

给开发者的ChatGPT提示词工程指南

【中文完整版全9集】第1集 引入-ChatGPT提示词工程师教程 吴恩达xOpenAI官方 【OpenAI官方 | 中文完整版】 吴恩达ChatGPT提示工程师初级到高级&#xff08;AI大神吴恩达教你写提示词&#xff09; ChatGPT Prompt Engineering for Development 基础大语言模型和指令精调大语言…

量子退火?这又是啥?居然撑起了第一家量子计算公司

组合优化问题&#xff0c;在应用数学和理论计算机科学领域&#xff0c;指的是在一个有限的对象里集中找出最优对象的一类课题。这类问题特征是可行解的集是离散或者可以简化到离散结果&#xff0c;并且目标是要找到最优解。当前&#xff0c;常见的组合优化问题通用版上包括旅行…

光量子计算公司宣布成立加拿大首个量子网络,大力推进量子创新

加拿大量子网络 光子量子计算的领导者Xanadu今天宣布与MaRS和Creative Destruction Lab&#xff08;CDL&#xff09;合作创建加拿大量子网络&#xff08;CQN&#xff09;。 CQN着手于加拿大多伦多的Xanadu、MaRS和CDL三个节点&#xff0c;为合作组织提供量子测试平台&#xf…

谷歌用量子处理器发现:光子能在混沌中保持稳健的束缚态

一圈超导量子比特可以容纳微波光子的“束缚态”&#xff0c;其中光子往往聚集在相邻的量子比特位点上。图片来源&#xff1a;Google Quantum AI 使用量子处理器&#xff0c;研究人员可以使微波光子具有异常的“粘性”。在诱使它们聚集成束缚态后&#xff0c;他们发现这些光子簇…

基于量桨搭建AI量子通信模拟平台,优化量子通信协议

点击左上方蓝字关注我们 项目背景 现阶段量子通讯协议的设计和优化依然停留在人工处理的阶段&#xff0c;距离迈向系统化工程处理依然有着不小的距离。导致目前量子通讯协议从研发到实验验证这一整套流程面临着周期长、成本高等问题。系统化的搭建模拟平台和引入先进的人工智能…

量子模拟器中的“弯曲时空”

光子盒研究院出品 当你想解释宇宙尺度的现象时&#xff0c;相对论很有效&#xff1a;比如黑洞碰撞时产生的引力波&#xff1b;量子理论在描述粒子尺度的现象时效果很好&#xff08;比如原子中单个电子的行为&#xff09;。但是&#xff0c;将这两者以一种完全令人满意的方式结合…

量子保密通信应用与技术探讨

源自&#xff1a; 信息通信技术与政策 作者&#xff1a;程明 张成良 唐建军 量子密钥在线与离线结合分发模式的应用范围不再局限于QKD网络的覆盖和能力&#xff0c;使得量子保密通信的应用场景得到较大拓展。 摘要 近年来,基于量子密钥分发的量子保密通信在应用方面进行了…

Infleqtion与Morningstar合作探索量子计算的新途径

&#xff08;图片来源&#xff1a;网络&#xff09; 量子计算服务商Infleqtion宣布&#xff0c;将Infleqtion的旗舰量子软件SuperstaQ整合到Morningstar投资和投资组合分析平台Morningstar Direct中。借助SuperstaQ的整合&#xff0c;通过Morningstar的实验室分析模块&#xff…

量子通信是不是伪科学?潘建伟这样回应

来源&#xff1a;科技日报 “墨子号”发射快三年了&#xff0c;到底有什么新发现&#xff1f;量子通信和公众有什么关联&#xff0c;到底是不是伪科学&#xff1f;10日&#xff0c;在全国政协十三届二次会议举行的记者会上&#xff0c;全国政协委员、中国科学技术大学常务副校长…

“走近”量子模拟

来源&#xff1a;中国军网 作者&#xff1a;张媛、张远、达平 当下&#xff0c;量子计算在先进材料以及生物化学模拟方面正崭露头角。因为量子力学解释了这些材料的基本物理特性&#xff0c;量子计算非常适合进行模拟。那么&#xff0c;什么是量子模拟&#xff1f;量子模拟有什…

“量子计算+通信”!玻色量子与中国移动研究院强强联合

​2023年3月12日&#xff0c;北京玻色量子科技有限公司&#xff08;后文简称“玻色量子”&#xff09;与中国移动通信有限公司研究院&#xff08;后文简称“中国移动研究院”&#xff09;达成合作&#xff0c;中国移动研究院院长黄宇红与玻色量子创始人&CEO文凯博士在玻色量…

量子信息技术(QIT)

信息技术IT(Information Technology),比特(bit)——20世纪的技术革命量子信息技术QIT(Quantum Information Technology),量子比特(qbit)——21世纪的技术革命量子信息论在科学方面有着深远的影响&#xff0c;改造量子力学基础&#xff0c;加速变革时空观&#xff0c;加深对定域…