使用双异步后,从 191s 优化到 2s

在这里插入图片描述

目录

    • 一、一般我会这样做:
      • 操作起来,如果文件比较多,数据量都很大的时候,会非常慢。
    • 二、谁写的?拖出去,斩了!
      • 优化1:先查询全部数据,缓存到map中,插入前再进行判断,速度快了很多。
      • 优化2:如果单个Excel文件过大,可以采用 异步 + 多线程 读取若干行,分批入库。
      • 优化3:如果文件数量过多,可以采一个Excel一个异步,形成完美的双异步读取插入。
      • 1、readExcelCacheAsync控制类
      • 2、分批读取超大Excel文件
      • 3、异步批量入库
      • 4、异步线程池工具类
        • @Async的作用就是异步处理任务。
        • 默认线程池的默认配置如下:
        • 也可以通过yml重新配置:
      • 5、异步失效的原因
    • 三、线程池中的核心线程数设置问题
      • 1、我记得有这样一个说法,CPU的处理器数量
      • 2、我记得大家都习惯性的将核心线程数CorePoolSize和最大线程数MaxPoolSize设置成一样的,都爱设置成200。
      • 3、经过数十次的测试
    • 四、通过EasyExcel读取并插入数据库
      • 1、ReadEasyExcelController
      • 2、ReadEasyExeclAsyncListener
      • 3、ReadEasyExeclServiceImpl
      • 4、UserInfo

大家好,我是哪吒。

在开发中,我们经常会遇到这样的需求,将Excel的数据导入数据库中。

一、一般我会这样做:

  1. 通过POI读取需要导入的Excel;
  2. 以文件名为表名、列头为列名、并将数据拼接成sql;
  3. 通过JDBC或mybatis插入数据库;

在这里插入图片描述

操作起来,如果文件比较多,数据量都很大的时候,会非常慢。

访问之后,感觉没什么反应,实际上已经在读取 + 入库了,只是比较慢而已。

读取一个10万行的Excel,居然用了191s,我还以为它卡死了呢!

private void readXls(String filePath, String filename) throws Exception {@SuppressWarnings("resource")XSSFWorkbook xssfWorkbook = new XSSFWorkbook(new FileInputStream(filePath));// 读取第一个工作表XSSFSheet sheet = xssfWorkbook.getSheetAt(0);// 总行数int maxRow = sheet.getLastRowNum();StringBuilder insertBuilder = new StringBuilder();insertBuilder.append("insert into ").append(filename).append(" ( UUID,");XSSFRow row = sheet.getRow(0);for (int i = 0; i < row.getPhysicalNumberOfCells(); i++) {insertBuilder.append(row.getCell(i)).append(",");}insertBuilder.deleteCharAt(insertBuilder.length() - 1);insertBuilder.append(" ) values ( ");StringBuilder stringBuilder = new StringBuilder();for (int i = 1; i <= maxRow; i++) {XSSFRow xssfRow = sheet.getRow(i);String id = "";String name = "";for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) {if (j == 0) {id = xssfRow.getCell(j) + "";} else if (j == 1) {name = xssfRow.getCell(j) + "";}}boolean flag = isExisted(id, name);if (!flag) {stringBuilder.append(insertBuilder);stringBuilder.append('\'').append(uuid()).append('\'').append(",");for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) {stringBuilder.append('\'').append(value).append('\'').append(",");}stringBuilder.deleteCharAt(stringBuilder.length() - 1);stringBuilder.append(" )").append("\n");}}List<String> collect = Arrays.stream(stringBuilder.toString().split("\n")).collect(Collectors.toList());int sum = JdbcUtil.executeDML(collect);
}private static boolean isExisted(String id, String name) {String sql = "select count(1) as num from " + static_TABLE + " where ID = '" + id + "' and NAME = '" + name + "'";String num = JdbcUtil.executeSelect(sql, "num");return Integer.valueOf(num) > 0;
}private static String uuid() {return UUID.randomUUID().toString().replace("-", "");
}

二、谁写的?拖出去,斩了!

优化1:先查询全部数据,缓存到map中,插入前再进行判断,速度快了很多。

优化2:如果单个Excel文件过大,可以采用 异步 + 多线程 读取若干行,分批入库。

在这里插入图片描述

优化3:如果文件数量过多,可以采一个Excel一个异步,形成完美的双异步读取插入。

在这里插入图片描述

使用双异步后,从 191s 优化到 2s,你敢信?

下面贴出异步读取Excel文件、并分批读取大Excel文件的关键代码。

1、readExcelCacheAsync控制类

@RequestMapping(value = "/readExcelCacheAsync", method = RequestMethod.POST)
@ResponseBody
public String readExcelCacheAsync() {String path = "G:\\测试\\data\\";try {// 在读取Excel之前,缓存所有数据USER_INFO_SET = getUserInfo();File file = new File(path);String[] xlsxArr = file.list();for (int i = 0; i < xlsxArr.length; i++) {File fileTemp = new File(path + "\\" + xlsxArr[i]);String filename = fileTemp.getName().replace(".xlsx", "");readExcelCacheAsyncService.readXls(path + filename + ".xlsx", filename);}} catch (Exception e) {logger.error("|#ReadDBCsv|#异常: ", e);return "error";}return "success";
}

2、分批读取超大Excel文件

@Async("async-executor")
public void readXls(String filePath, String filename) throws Exception {@SuppressWarnings("resource")XSSFWorkbook xssfWorkbook = new XSSFWorkbook(new FileInputStream(filePath));// 读取第一个工作表XSSFSheet sheet = xssfWorkbook.getSheetAt(0);// 总行数int maxRow = sheet.getLastRowNum();logger.info(filename + ".xlsx,一共" + maxRow + "行数据!");StringBuilder insertBuilder = new StringBuilder();insertBuilder.append("insert into ").append(filename).append(" ( UUID,");XSSFRow row = sheet.getRow(0);for (int i = 0; i < row.getPhysicalNumberOfCells(); i++) {insertBuilder.append(row.getCell(i)).append(",");}insertBuilder.deleteCharAt(insertBuilder.length() - 1);insertBuilder.append(" ) values ( ");int times = maxRow / STEP + 1;//logger.info("将" + maxRow + "行数据分" + times + "次插入数据库!");for (int time = 0; time < times; time++) {int start = STEP * time + 1;int end = STEP * time + STEP;if (time == times - 1) {end = maxRow;}if(end + 1 - start > 0){//logger.info("第" + (time + 1) + "次插入数据库!" + "准备插入" + (end + 1 - start) + "条数据!");//readExcelDataAsyncService.readXlsCacheAsync(sheet, row, start, end, insertBuilder);readExcelDataAsyncService.readXlsCacheAsyncMybatis(sheet, row, start, end, insertBuilder);}}
}

3、异步批量入库

@Async("async-executor")
public void readXlsCacheAsync(XSSFSheet sheet, XSSFRow row, int start, int end, StringBuilder insertBuilder) {StringBuilder stringBuilder = new StringBuilder();for (int i = start; i <= end; i++) {XSSFRow xssfRow = sheet.getRow(i);String id = "";String name = "";for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) {if (j == 0) {id = xssfRow.getCell(j) + "";} else if (j == 1) {name = xssfRow.getCell(j) + "";}}// 先在读取Excel之前,缓存所有数据,再做判断boolean flag = isExisted(id, name);if (!flag) {stringBuilder.append(insertBuilder);stringBuilder.append('\'').append(uuid()).append('\'').append(",");for (int j = 0; j < row.getPhysicalNumberOfCells(); j++) {stringBuilder.append('\'').append(value).append('\'').append(",");}stringBuilder.deleteCharAt(stringBuilder.length() - 1);stringBuilder.append(" )").append("\n");}}List<String> collect = Arrays.stream(stringBuilder.toString().split("\n")).collect(Collectors.toList());if (collect != null && collect.size() > 0) {int sum = JdbcUtil.executeDML(collect);}
}private boolean isExisted(String id, String name) {return ReadExcelCacheAsyncController.USER_INFO_SET.contains(id + "," + name);
}

4、异步线程池工具类

@Async的作用就是异步处理任务。
  1. 在方法上添加@Async,表示此方法是异步方法;
  2. 在类上添加@Async,表示类中的所有方法都是异步方法;
  3. 使用此注解的类,必须是Spring管理的类;
  4. 需要在启动类或配置类中加入@EnableAsync注解,@Async才会生效;

在使用@Async时,如果不指定线程池的名称,也就是不自定义线程池,@Async是有默认线程池的,使用的是Spring默认的线程池SimpleAsyncTaskExecutor。

默认线程池的默认配置如下:
  1. 默认核心线程数:8;
  2. 最大线程数:Integet.MAX_VALUE;
  3. 队列使用LinkedBlockingQueue;
  4. 容量是:Integet.MAX_VALUE;
  5. 空闲线程保留时间:60s;
  6. 线程池拒绝策略:AbortPolicy;

从最大线程数可以看出,在并发情况下,会无限制的创建线程,我勒个吗啊。

也可以通过yml重新配置:
spring:task:execution:pool:max-size: 10core-size: 5keep-alive: 3squeue-capacity: 1000thread-name-prefix: my-executor

也可以自定义线程池,下面通过简单的代码来实现以下@Async自定义线程池。

@EnableAsync// 支持异步操作
@Configuration
public class AsyncTaskConfig {/*** com.google.guava中的线程池* @return*/@Bean("my-executor")public Executor firstExecutor() {ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("my-executor").build();// 获取CPU的处理器数量int curSystemThreads = Runtime.getRuntime().availableProcessors() * 2;ThreadPoolExecutor threadPool = new ThreadPoolExecutor(curSystemThreads, 100,200, TimeUnit.SECONDS,new LinkedBlockingQueue<>(), threadFactory);threadPool.allowsCoreThreadTimeOut();return threadPool;}/*** Spring线程池* @return*/@Bean("async-executor")public Executor asyncExecutor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();// 核心线程数taskExecutor.setCorePoolSize(24);// 线程池维护线程的最大数量,只有在缓冲队列满了之后才会申请超过核心线程数的线程taskExecutor.setMaxPoolSize(200);// 缓存队列taskExecutor.setQueueCapacity(50);// 空闲时间,当超过了核心线程数之外的线程在空闲时间到达之后会被销毁taskExecutor.setKeepAliveSeconds(200);// 异步方法内部线程名称taskExecutor.setThreadNamePrefix("async-executor-");/*** 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略* 通常有以下四种策略:* ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。* ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。* ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)* ThreadPoolExecutor.CallerRunsPolicy:重试添加当前的任务,自动重复调用 execute() 方法,直到成功*/taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());taskExecutor.initialize();return taskExecutor;}
}

在这里插入图片描述

5、异步失效的原因

  1. 注解@Async的方法不是public方法;
  2. 注解@Async的返回值只能为void或Future;
  3. 注解@Async方法使用static修饰也会失效;
  4. 没加@EnableAsync注解;
  5. 调用方和@Async不能在一个类中;
  6. 在Async方法上标注@Transactional是没用的,但在Async方法调用的方法上标注@Transcational是有效的;

三、线程池中的核心线程数设置问题

有一个问题,一直没时间摸索,线程池中的核心线程数CorePoolSize、最大线程数MaxPoolSize,设置成多少,最合适,效率最高。

借着这个机会,测试一下。

1、我记得有这样一个说法,CPU的处理器数量

将核心线程数CorePoolSize设置成CPU的处理器数量,是不是效率最高的?

// 获取CPU的处理器数量
int curSystemThreads = Runtime.getRuntime().availableProcessors() * 2;

Runtime.getRuntime().availableProcessors()获取的是CPU核心线程数,也就是计算资源。

  • CPU密集型,线程池大小设置为N,也就是和cpu的线程数相同,可以尽可能地避免线程间上下文切换,但在实际开发中,一般会设置为N+1,为了防止意外情况出现线程阻塞,如果出现阻塞,多出来的线程会继续执行任务,保证CPU的利用效率。
  • IO密集型,线程池大小设置为2N,这个数是根据业务压测出来的,如果不涉及业务就使用推荐。

在实际中,需要对具体的线程池大小进行调整,可以通过压测及机器设备现状,进行调整大小。

如果线程池太大,则会造成CPU不断的切换,对整个系统性能也不会有太大的提升,反而会导致系统缓慢。

我的电脑的CPU的处理器数量是24。

那么一次读取多少行最合适呢?

测试的Excel中含有10万条数据,10万/24 = 4166,那么我设置成4200,是不是效率最佳呢?

测试的过程中发现,好像真的是这样的。

2、我记得大家都习惯性的将核心线程数CorePoolSize和最大线程数MaxPoolSize设置成一样的,都爱设置成200。

是随便写的,还是经验而为之?

测试发现,当你将核心线程数CorePoolSize和最大线程数MaxPoolSize都设置为200的时候,第一次它会同时开启150个线程,来进行工作。

这个是为什么?

在这里插入图片描述

3、经过数十次的测试

  1. 发现核心线程数好像差别不大
  2. 每次读取和入库的数量是关键,不能太多,因为每次入库会变慢;
  3. 也不能太少,如果太少,超过了150个线程,就会造成线程阻塞,也会变慢;

在这里插入图片描述

四、通过EasyExcel读取并插入数据库

EasyExcel的方式,我就不写双异步优化了,大家切记陷入低水平勤奋的怪圈。

1、ReadEasyExcelController

@RequestMapping(value = "/readEasyExcel", method = RequestMethod.POST)
@ResponseBody
public String readEasyExcel() {try {String path = "G:\\测试\\data\\";String[] xlsxArr = new File(path).list();for (int i = 0; i < xlsxArr.length; i++) {String filePath = path + xlsxArr[i];File fileTemp = new File(path + xlsxArr[i]);String fileName = fileTemp.getName().replace(".xlsx", "");List<UserInfo> list = new ArrayList<>();EasyExcel.read(filePath, UserInfo.class, new ReadEasyExeclAsyncListener(readEasyExeclService, fileName, batchCount, list)).sheet().doRead();}}catch (Exception e){logger.error("readEasyExcel 异常:",e);return "error";}return "suceess";
}

2、ReadEasyExeclAsyncListener

public ReadEasyExeclService readEasyExeclService;// 表名public String TABLE_NAME;// 批量插入阈值private int BATCH_COUNT;// 数据集合private List<UserInfo> LIST;public ReadEasyExeclAsyncListener(ReadEasyExeclService readEasyExeclService, String tableName, int batchCount, List<UserInfo> list) {this.readEasyExeclService = readEasyExeclService;this.TABLE_NAME = tableName;this.BATCH_COUNT = batchCount;this.LIST = list;}@Overridepublic void invoke(UserInfo data, AnalysisContext analysisContext) {data.setUuid(uuid());data.setTableName(TABLE_NAME);LIST.add(data);if(LIST.size() >= BATCH_COUNT){// 批量入库readEasyExeclService.saveDataBatch(LIST);}}@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {if(LIST.size() > 0){// 最后一批入库readEasyExeclService.saveDataBatch(LIST);}}public static String uuid() {return UUID.randomUUID().toString().replace("-", "");}
}

3、ReadEasyExeclServiceImpl

@Service
public class ReadEasyExeclServiceImpl implements ReadEasyExeclService {@Resourceprivate ReadEasyExeclMapper readEasyExeclMapper;@Overridepublic void saveDataBatch(List<UserInfo> list) {// 通过mybatis入库readEasyExeclMapper.saveDataBatch(list);// 通过JDBC入库// insertByJdbc(list);list.clear();}private void insertByJdbc(List<UserInfo> list){List<String> sqlList = new ArrayList<>();for (UserInfo u : list){StringBuilder sqlBuilder = new StringBuilder();sqlBuilder.append("insert into ").append(u.getTableName()).append(" ( UUID,ID,NAME,AGE,ADDRESS,PHONE,OP_TIME ) values ( ");sqlBuilder.append("'").append(ReadEasyExeclAsyncListener.uuid()).append("',").append("'").append(u.getId()).append("',").append("'").append(u.getName()).append("',").append("'").append(u.getAge()).append("',").append("'").append(u.getAddress()).append("',").append("'").append(u.getPhone()).append("',").append("sysdate )");sqlList.add(sqlBuilder.toString());}JdbcUtil.executeDML(sqlList);}
}

4、UserInfo

@Data
public class UserInfo {private String tableName;private String uuid;@ExcelProperty(value = "ID")private String id;@ExcelProperty(value = "NAME")private String name;@ExcelProperty(value = "AGE")private String age;@ExcelProperty(value = "ADDRESS")private String address;@ExcelProperty(value = "PHONE")private String phone;
}

🏆哪吒多年工作总结:Java学习路线总结,搬砖工逆袭Java架构师

华为OD机试 2023B卷题库疯狂收录中,刷题点这里

刷的越多,抽中的概率越大,每一题都有详细的答题思路、详细的代码注释、样例测试,发现新题目,随时更新,全天CSDN在线答疑。

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

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

相关文章

java xxe漏洞利用_【技术分享】XXE漏洞攻防之我见

作者&#xff1a;激越王预估稿费&#xff1a;400RMB投稿方式&#xff1a;发送邮件至linwei#360.cn&#xff0c;或登陆网页版在线投稿你是否听说过xml注入攻击呢&#xff0c;或者对它只知其一不知其二呢&#xff1f;现在让我们从xml相关基础知识开始&#xff0c;一步步了解xml攻…

线谱法 时钟分量的提取 matlab,LMD局域均值分解的matlab程序及示例

说明&#xff1a;研究LMD局域均值分解有3个月左右&#xff0c;能找到的相关文章也基本上看了一遍&#xff0c;觉得是个很好的方法&#xff0c;号称是EMD经验模态分解的改进版。但是网络上一直没有找到该算法的matlab程序&#xff0c;只见文章说的天花乱坠。后来自己写了一个&am…

php csrf攻击 xss区别,XSS与CSRF攻击及防御方法

前言web安全这词可能对于服务端工程师来说更加“眼熟”&#xff0c;部分前端工程师并不是十分了解&#xff0c;今天就来讲讲XSS攻击与CSRF攻击及防御方法XSSXSS (Cross Site Scripting)&#xff0c;即跨站脚本攻击&#xff0c;是一种常见于 Web 应用中的计算机安全漏洞。大部分…

matlab各个指令的含义,[MATLAB基础] 求解这段指令的意思,越详细越好,谢谢啦

求解这段指令的意思&#xff0c;越详细越好&#xff0c;谢谢啦 function [Kp,T2]KPCA(ax,ay)[Nx]size(ax);mean_X mean(ax);axbax;std_Xstd(ax);axax-mean_X(ones(Nx,1),:);std_X(find(std_X0))1;%数据预处理axax./std_X(ones(Nx,1),:);c10000;% gama0.05;% ni1;% F1ax(1,:);% …

php+js实现弹幕,jquery.barrager.js-专业的网页弹幕插件

jquery.barrager.js是一款专业的网页弹幕插件。它支持显示图片,文字以及超链接。支持自定义弹幕的速度、高度、颜色、数量等。能轻松集成到论坛,博客等网站中。由于IE9以下的IE浏览器不兼容CSS圆角,采用兼容样式,可单独设置弹幕的颜色,属性为old_ie_color,建议不要与网页主背景…

zend studio php 5.5,Zend Studio使用教程:在Zend Studio中调试PHP(5/5)

本教程将教会您如何调试文件和应用程序以便从您的PHP代码中获取最大的效率和准确性。Zend Studio的调试功能可以检查并诊断PHP代码在本地或远程服务器上的错误。调试器允许您通过设置断点、暂停启动的程序、单步调试代码和检查变量的内容来控制程序的执行。调试应该在您的脚本和…

oracle 安装乱码,linux安装Oracle中文乱码问题汇总

解决oracle中文显示乱码有三层地方需要调整或者修改第一层&#xff1a;操作系统层1.首先查看linux是否有安装中文字符集&#xff0c;locale -a2.设置用户的中文字符集查看到linux安装了中文字符集&#xff0c;那么oracle用户下面要设置中文字符集vi /etc/locale.conf # centos7…

php 路径有汉字,路径文字工具

大家可能会在视频上面看到一些不规则的字幕吧&#xff0c;比如&#xff1a;圆形、椭圆、波浪形等等&#xff0c;这些也叫做路径文字&#xff0c;就是在给视频添加字幕的时候&#xff0c;让文字按着自己描绘的路径来排列&#xff0c;这样就得到了路径文字。原理很简单&#xff0…

qq linux版本下载官网下载,腾讯QQ For Linux

安装帮助如何选择安装包&#xff1f;Linux QQ 目前支持x64(x86_64、amd64)、arm64(aarch64)、mips64(mips64el)三种架构&#xff0c;每种架构支持Debian系、红帽系、Arch Linux系、其它发行版中的一种或几种(未来可能继续扩充)。每一次发布均会提供架构和发行版的若干种组合支持…

linux ip隧道技术,linux之IP隧道配置

本文系统Centos6.0在这里我就不讲什么隧道、IP隧道技术了&#xff1b;lvs的三种模式也不说了我这里隧道说白了就是不同机房&#xff0c;不同公网IP&#xff0c;怎么让他们实现局域网的效果&#xff0c;配置同一网段的私网IP&#xff1b;可以实现互联互通&#xff1b;写这篇文章…

kali linux conky配置文件,7个美丽的Conky配置为您的Linux桌面 | MOS86

现在&#xff0c;大多数Linux用户非常熟悉Conky包括多少人都没有今天我们Note:其中一些不仅仅是一个习惯。conkyrc文件。许多都配有专门的字体或附加软件&#xff0c;有些则作为更大的桌面主题的一部分打包。此处列出的所有配置都提供了到原始下载位置以及每个包的链接此外&…

sd卡linux错误检测,android系统正在准备SD卡正在检测是否有错误且SD卡无法读取解决办法...

手机android系统&#xff0c;也许您会碰到这样的情况。错误提示&#xff1a;正在准备SD卡 正在检测是否有错误。这时sd卡(即内存卡)不能正常使用&#xff0c;不管手机自带的程序&#xff0c;还是通过usb口连接到电脑都无法识别sd卡。这可能是由于没有正常卸载sd卡导致的原因。比…

C语言顺序结构程序设计PPT,C语言习题集与实验指导 教学课件 伍鹏、杜红、王圆妹、邓绍金 第3章 顺序结构程序设计.pdf...

[摘要]第3章 顺序结构程序设计 第3章 顺序结构程序设计 当你对C语言程序设计有了一定了解和掌握后&#xff0c; 在处理一些简单的任务时&#xff0c;若想根据程序书写的过程 顺序执行程序&#xff0c;这时应该如何处理呢&#xff1f; •顺序结构 •顺序结构 程序的三种结构 程序…

three.js使用精灵模型Sprite渲染森林

效果&#xff1a; 源码&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><div class"box-right&quo…

鸿蒙系统操作界面布局,华为鸿蒙操作系统大曝光

描述华为鸿蒙操作系统大曝光5月21日&#xff0c;华为消费者业务CEO余承东透露&#xff0c;面向下一代技术而设计的华为操作系统“鸿蒙”&#xff0c;最早将于今秋面市。而就在前天&#xff0c;环球时报(Global Times)发出推文表示&#xff1a;有消息人士称&#xff0c;华为正在…

android 高德获取省市,高德地图定位获取当前地址城市街道等详细信息(全部代码)...

自动定位后弹窗信息&#xff0c;包含省市县镇区路门牌号(效果图如下)代码↓↓↓获取地理位置var mapObj new AMap.Map(iCenter);mapObj.plugin(AMap.Geolocation, function () {geolocation new AMap.Geolocation({enableHighAccuracy: true, // 是否使用高精度定位&#xff…

鸿蒙系统新手教程,鸿蒙灭神决新手入门全流程图文攻略

鸿蒙灭神决新手入门全流程图文攻略2019-03-21 15:04:13来源&#xff1a;天天RPG编辑&#xff1a;野狐禅评论(0)中后期回归主题&#xff0c;如果还是打不过神器2&#xff0c;可以先到“中级挑战”这里完成第一排的四项挑战&#xff0c;可以获得四件道具。从这里开始由于我们刷木…

html添加工具栏,添加带有命令的工具栏 (HTML)

添加带有命令的工具栏 (HTML)03/04/2016本文内容[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发&#xff0c;请参阅 最新文档 ]ToolBar 是一个简单的控件&#xff0c;用于解决命令扩展问题。它具有一个 …

用计算机解决问题 评课稿,总结反思:二年级数学lbrack;解决问题rsqb;评课稿

二年级数学《解决问题》评课稿二年级数学《解决问题》评课稿今天上午听了一节二年级数学上册用加减混合的常识《解决问题》的课&#xff0c;受益匪浅。我觉得这节课是顺利的&#xff0c;有待我们学习跟借鉴。雷老师虽未年过五旬&#xff0c;但他不服老的敬业精神&#xff0c;以…

计算机信息科学蔺泽浩,上海交通大学计算机科学与工程系(CSE)

脑机交互的多模态疲劳驾驶检测系统本系统通过获取驾驶员的脑电信号(EEG)、眼电信号(EOG)、握力信号和Kinect图像&#xff0c;从生理信号和行为特征中提取与疲劳相关的特征&#xff0c;利用机器学习方法建立疲劳检测模型&#xff0c;实现驾驶员疲劳状态的度量与预测。与传统的基…