18.将文件上传至云服务器 + 优化网站的性能
目录
1.将文件上传至云服务器
1.1 处理上传头像逻辑
1.1.1 客户端上传
1.1.2 服务器直传
2.优化网站的性能
2.1 本地缓存优化查询方法
2.2 压力测试
1.将文件上传至云服务器
- 客户端上传:客户端将数据提交给云服务器,并等待其响应;用户上传头像时,将表单数据提交给服务器
- 服务器直传:应用服务器将数据直接提交给云服务器,并等待其响应;分享时,服务端将自动生成的图片,直接提交给云服务器
使用七牛云服务器
导入依赖:
<!-- https://mvnrepository.com/artifact/com.qiniu/qiniu-java-sdk -->
<dependency><groupId>com.qiniu</groupId><artifactId>qiniu-java-sdk</artifactId><version>7.12.1</version>
</dependency>
在 application.properties 中配置:
# qiniu
qiniu.key.access=NHzlA2MRle10vB0wNeO54aGS-tMjEpO5BiIrflz9
qiniu.key.secret=qicgWpPOslm5_dFu_j_94r5gUcKm_UekhT2MMLPf
qiniu.bucket.header.name=communityheader123321
quniu.bucket.header.url=http://s6sc3za8f.hb-bkt.clouddn.com
qiniu.bucket.share.name=communityshare123321
qiniu.bucket.share.url=http://s6scgzhqs.hb-bkt.clouddn.com
1.1 处理上传头像逻辑
1.1.1 客户端上传
打开 UserController 类:
- 注入上述的两个 key
- 注入有关头像的空间内容
- 废弃原来上传头像方法:上传头像因为有表单,所以在客户端上传,表单直接提交给七牛云,废弃此方法
- 上传文件同样废弃
- 在打开用户设置的页面时需要生成凭证(设置上传文件名称,响应信息),将凭证写到表单中,当打开表单时,表单中应该有凭证
- 最后传给模板
- 还需要添加一个方法:在表单中将数据提交给七牛云,七牛云返回一个消息,然后将 User 表中的 headurl 做一个更新,更新为七牛云的路径
@Value("${qiniu.key.access}")private String accessKey;@Value("${qiniu.key.secret}")private String secretKey;@Value("${qiniu.bucket.header.name}")private String headerBucketName;@Value("${quniu.bucket.header.url}")private String headerBucketUrl;@LoginRequired@RequestMapping(path = "/setting", method = RequestMethod.GET)//添加方法使得浏览器通过方法访问到设置的页面public String getSettingPage(Model model) {// 上传文件名称String fileName = CommunityUtil.generateUUID();// 设置响应信息StringMap policy = new StringMap();policy.put("returnBody", CommunityUtil.getJSONString(0));// 生成上传凭证Auth auth = Auth.create(accessKey, secretKey);String uploadToken = auth.uploadToken(headerBucketName, fileName, 3600, policy);model.addAttribute("uploadToken", uploadToken);model.addAttribute("fileName", fileName);return "/site/setting";}// 更新头像路径@RequestMapping(path = "/header/url", method = RequestMethod.POST)@ResponseBodypublic String updateHeaderUrl(String fileName) {if (StringUtils.isBlank(fileName)) {return CommunityUtil.getJSONString(1, "文件名不能为空!");}String url = headerBucketUrl + "/" + fileName;userService.updateHeader(hostHolder.getUser().getId(), url);return CommunityUtil.getJSONString(0);}
再处理表单 setting.html:
<!-- 上传头像 --><h6 class="text-left text-info border-bottom pb-2">上传头像</h6><!--上传到本地--><!--<form class="mt-5" method="post" enctype="multipart/form-data" th:action="@{/user/upload}"><div class="form-group row mt-4"><label for="head-image" class="col-sm-2 col-form-label text-right">选择头像:</label><div class="col-sm-10"><div class="custom-file"><input type="file" th:class="|custom-file-input ${error!=null?'is-invalid':''}|"id="head-image" name="headerImage" lang="es" required=""><label class="custom-file-label" for="head-image" data-browse="文件">选择一张图片</label><div class="invalid-feedback" th:text="${error}">该账号不存在!</div></div></div></div><div class="form-group row mt-4"><div class="col-sm-2"></div><div class="col-sm-10 text-center"><button type="submit" class="btn btn-info text-white form-control">立即上传</button></div></div></form>--><!--上传到七牛云--><form class="mt-5" id="uploadForm"><div class="form-group row mt-4"><label for="head-image" class="col-sm-2 col-form-label text-right">选择头像:</label><div class="col-sm-10"><div class="custom-file"><input type="hidden" name="token" th:value="${uploadToken}"><input type="hidden" name="key" th:value="${fileName}"><input type="file" class="custom-file-input" id="head-image" name="file" lang="es" required=""><label class="custom-file-label" for="head-image" data-browse="文件">选择一张图片</label><div class="invalid-feedback">该账号不存在!</div></div></div></div><div class="form-group row mt-4"><div class="col-sm-2"></div><div class="col-sm-10 text-center"><button type="submit" class="btn btn-info text-white form-control">立即上传</button></div></div></form>
在 static 包下 js 包新建 setting.js:
$(function(){$("#uploadForm").submit(upload);
});function upload() {$.ajax({url: "http://upload-z1.qiniup.com",method: "post",processData: false,contentType: false,data: new FormData($("#uploadForm")[0]),success: function(data) {if(data && data.code == 0) {// 更新头像访问路径$.post(CONTEXT_PATH + "/user/header/url",{"fileName":$("input[name='key']").val()},function(data) {data = $.parseJSON(data);if(data.code == 0) {window.location.reload();} else {alert(data.msg);}});} else {alert("上传失败!");}}});return false;
}


1.1.2 服务器直传
需要重构分享相关的功能,打开 ShareController :
- 注入分享空间的 url
- 修改返回浏览器的路径:七牛云空间路径 = 空间 url + / + 图片名字
- 废弃从本地获取图片传给客户端的方法:传给七牛云之后,通过七牛云获取图片
@Value("${qiniu.bucket.share.url}")private String shareBucketUrl;@RequestMapping(path = "/share", method = RequestMethod.GET)@ResponseBodypublic String share(String htmlUrl) {// 文件名String fileName = CommunityUtil.generateUUID();// 异步生成长图Event event = new Event().setTopic(TOPIC_SHARE).setData("htmlUrl", htmlUrl).setData("fileName", fileName).setData("suffix", ".png");//触发事件eventProducer.fireEvent(event);// 返回访问路径Map<String, Object> map = new HashMap<>();// map.put("shareUrl", domain + contextPath + "/share/image/" + fileName);map.put("shareUrl", shareBucketUrl + "/" + fileName);return CommunityUtil.getJSONString(0, null, map);}// 废弃// 获取长图@RequestMapping(path = "/share/image/{fileName}", method = RequestMethod.GET)public void getShareImage(@PathVariable("fileName") String fileName, HttpServletResponse response) {if (StringUtils.isBlank(fileName)) {throw new IllegalArgumentException("文件名不能为空!");}response.setContentType("image/png");File file = new File(wkImageStorage + "/" + fileName + ".png");try {OutputStream os = response.getOutputStream();FileInputStream fis = new FileInputStream(file);byte[] buffer = new byte[1024];int b = 0;while ((b = fis.read(buffer)) != -1) {os.write(buffer, 0, b);}} catch (IOException e) {logger.error("获取长图失败: " + e.getMessage());}}
修改 EventConsumer,逻辑是在消费者中体现
- 在消费者中消费事件,传入两个 key 和上传空间的 name
- 注入 ThreadPoolTaskScheduler
- 在消费分享事件中,在执行生成图片时,启用定时器,监视该图片,一旦生成,则上传至七牛云.
// 消费分享事件@KafkaListener(topics = TOPIC_SHARE)public void handleShareMessage(ConsumerRecord record) {if (record == null || record.value() == null) {logger.error("消息的内容为空!");return;}Event event = JSONObject.parseObject(record.value().toString(), Event.class);if (event == null) {logger.error("消息格式错误!");return;}//获取 html、文件名、后缀String htmlUrl = (String) event.getData().get("htmlUrl");String fileName = (String) event.getData().get("fileName");String suffix = (String) event.getData().get("suffix");//拼接参数String cmd = wkImageCommand + " --quality 75 "+ htmlUrl + " " + wkImageStorage + "/" + fileName + suffix;//执行命令try {Runtime.getRuntime().exec(cmd);logger.info("生成长图成功: " + cmd);} catch (IOException e) {logger.error("生成长图失败: " + e.getMessage());}// 启用定时器,监视该图片,一旦生成了,则上传至七牛云.UploadTask task = new UploadTask(fileName, suffix);//触发定时器执行Future future = taskScheduler.scheduleAtFixedRate(task, 500);//完成任务后定时器关闭task.setFuture(future);}//相当于线程体class UploadTask implements Runnable {// 文件名称private String fileName;// 文件后缀private String suffix;// 启动任务的返回值private Future future;// 开始时间private long startTime;// 上传次数private int uploadTimes;public UploadTask(String fileName, String suffix) {this.fileName = fileName;this.suffix = suffix;this.startTime = System.currentTimeMillis();}public void setFuture(Future future) {this.future = future;}@Overridepublic void run() {// 生成失败if (System.currentTimeMillis() - startTime > 30000) {logger.error("执行时间过长,终止任务:" + fileName);future.cancel(true);return;}// 上传失败if (uploadTimes >= 3) {logger.error("上传次数过多,终止任务:" + fileName);future.cancel(true);return;}//没有上述情况继续执行相关逻辑//从本地中寻找文件String path = wkImageStorage + "/" + fileName + suffix;//本地路径File file = new File(path);if (file.exists()) {logger.info(String.format("开始第%d次上传[%s].", ++uploadTimes, fileName));// 设置响应信息StringMap policy = new StringMap();// 成功返回0policy.put("returnBody", CommunityUtil.getJSONString(0));// 生成上传凭证Auth auth = Auth.create(accessKey, secretKey);String uploadToken = auth.uploadToken(shareBucketName, fileName, 3600, policy);// 指定上传机房UploadManager manager = new UploadManager(new Configuration(Zone.zone1()));try {// 开始上传图片Response response = manager.put(path, fileName, uploadToken, null, "image/" + suffix, false);// 处理响应结果JSONObject json = JSONObject.parseObject(response.bodyString());if (json == null || json.get("code") == null || !json.get("code").toString().equals("0")) {logger.info(String.format("第%d次上传失败[%s].", uploadTimes, fileName));} else {logger.info(String.format("第%d次上传成功[%s].", uploadTimes, fileName));future.cancel(true);}} catch (QiniuException e) {logger.info(String.format("第%d次上传失败[%s].", uploadTimes, fileName));}} else {logger.info("等待图片生成[" + fileName + "].");}}}
2.优化网站的性能
本地缓存:将数据缓存在应用服务器上,性能最好;常用的缓存工具:Ehcache、Guava、Caffeine等
分布式缓存:将数据缓存在 NoSQL 数据库上,跨服务器;常用缓存工具:MemCache、Redis等
多级缓存:一级缓存 > 二级缓存 > DB;避免缓存雪崩(缓存失效,大量请求直达DB),提高系统的可用性
2.1 本地缓存优化查询方法
本地缓存主要使用 Caffeine 工具,导入依赖:
<dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>2.7.0</version></dependency>
设置自定义参数:
# caffeine
caffeine.posts.max-size=15
caffeine.posts.expire-seconds=180
优化查询方法(discussPostService):
- 初始化 Logger,记录日志
- 注入上述申明参数
- Caffeine核心接口: Cache, LoadingCache(同步缓存:多个线程同时访问缓存中的数据,但是缓存中没有数据,让多个线程排队等待,然后缓存去数据库中取), AsyncLoadingCache(异步缓存:支持并发同时取数据)
- 声明帖子列表缓存,使用 LoadingCache<String, List<DiscussPost>>(使用 key 缓存 value)
- 声明帖子总数缓存,使用 LoadingCache<Integer, Integer>
- 在服务启动或者首次调用 DiscussPostService,初始化一次上述两个缓存即可
- 给当前类新增初始化方法,添加注解 @PostConstruct,初始化帖子列表缓存和帖子总数缓存
- 在查询某一页的方法中需要启动缓存的条件:缓存热门帖子(orderMode == 1)并且缓存首页(访问首页的时候,userId 是不传为0),缓存的是一页的数据(key 为 offset 和 limit 组合);否则访问数据库,在访问之前记录一下日志(load post list from DB.)
- 在查询总数的方法中:用户查看自己帖子的时候不需要缓存,但是当 userId == 0 为首页查询,需要缓存帖子总数
private static final Logger logger = LoggerFactory.getLogger(DiscussPostService.class);@Value("${caffeine.posts.max-size}")private int maxSize;@Value("${caffeine.posts.expire-seconds}")private int expireSeconds;// Caffeine核心接口: Cache, LoadingCache, AsyncLoadingCache// 帖子列表缓存private LoadingCache<String, List<DiscussPost>> postListCache;// 帖子总数缓存private LoadingCache<Integer, Integer> postRowsCache;@PostConstructpublic void init() {// 初始化帖子列表缓存postListCache = Caffeine.newBuilder().maximumSize(maxSize)//缓存最大数据量.expireAfterWrite(expireSeconds, TimeUnit.SECONDS)//把缓存写入缓存空间多长时间自动过期.build(new CacheLoader<String, List<DiscussPost>>() {//当尝试从缓存中取数据,caffeine会看缓存是否有数据://没有,需要提供一个查询的方法,load就是实现这个查询方法@Nullable@Overridepublic List<DiscussPost> load(@NonNull String key) throws Exception {//实现访问数据库查数据if (key == null || key.length() == 0) {throw new IllegalArgumentException("参数错误!");}//不为空,解析 key(offset + ":" + limit),:进行切割String[] params = key.split(":");if (params == null || params.length != 2) {throw new IllegalArgumentException("参数错误!");}int offset = Integer.valueOf(params[0]);int limit = Integer.valueOf(params[1]);// 二级缓存: Redis -> mysqllogger.debug("load post list from DB.");//调用discussPostMapper查询数据(userId = 0 orderMode = 1)return discussPostMapper.selectDiscussPosts(0, offset, limit, 1);}});// 初始化帖子总数缓存postRowsCache = Caffeine.newBuilder().maximumSize(maxSize).expireAfterWrite(expireSeconds, TimeUnit.SECONDS).build(new CacheLoader<Integer, Integer>() {@Nullable@Overridepublic Integer load(@NonNull Integer key) throws Exception {logger.debug("load post rows from DB.");return discussPostMapper.selectDiscussPostRows(key);}});}//声明一个业务方法:查询某一页的方法,返回类型是集合public List<DiscussPost> findDiscussPosts(int userId, int offset, int limit, int orderMode) {//缓存热门帖子(orderMode == 1)并且缓存首页(访问首页的时候,userId 是不传为0)// 缓存的是一页的数据(key 为 offset 和 limit 组合)if (userId == 0 && orderMode == 1) {return postListCache.get(offset + ":" + limit);}//否则访问数据库,在访问之前记录一下日志logger.debug("load post list from DB.");return discussPostMapper.selectDiscussPosts(userId, offset, limit, orderMode);}//查询行数的方法public int findDiscussPostRows(int userId) {if (userId == 0) {return postRowsCache.get(userId);}logger.debug("load post rows from DB.");return discussPostMapper.selectDiscussPostRows(userId);}
测试类:
package com.example.demo;import com.example.demo.entity.DiscussPost;
import com.example.demo.service.DiscussPostService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;import java.util.Date;@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = DemoApplication.class)
public class CaffeineTests {@Autowiredprivate DiscussPostService postService;@Testpublic void initDataForTest() {for (int i = 0; i < 300000; i++) {DiscussPost post = new DiscussPost();post.setUserId(111);post.setTitle("互联网求职暖春计划");post.setContent("今年的就业形势,确实不容乐观");post.setCreateTime(new Date());post.setScore(Math.random() * 2000);postService.addDiscussPost(post);}}@Testpublic void testCache() {System.out.println(postService.findDiscussPosts(0, 0, 10, 1));System.out.println(postService.findDiscussPosts(0, 0, 10, 1));System.out.println(postService.findDiscussPosts(0, 0, 10, 1));System.out.println(postService.findDiscussPosts(0, 0, 10, 0));}}
2.2 压力测试
使用 jmeter 工具测试:
未添加缓存:


添加缓存:


相关文章:
18.将文件上传至云服务器 + 优化网站的性能
目录 1.将文件上传至云服务器 1.1 处理上传头像逻辑 1.1.1 客户端上传 1.1.2 服务器直传 2.优化网站的性能 2.1 本地缓存优化查询方法 2.2 压力测试 1.将文件上传至云服务器 客户端上传:客户端将数据提交给云服务器,并等待其响应;用户…...
Linux: module: kheaders;CONFIG_IKHEADERS
文章目录 参考错误开一个玩笑。configcommit参考 https://github.com/iovisor/bcc/pull/2312 https://github.com/iovisor/bcc/pull/3588 https://bugs.gentoo.org/809347 https://lore.kernel.org/lkml/20190408212855.233198-1-joel@joelfernandes.org/ 错误 <built-in…...
Page 251~254 Win32 GUI项目
win32_gui 源代码: #if defined(UNICODE) && !defined(_UNICODE)#define _UNICODE #elif defined(_UNICODE) && !defined(UNICODE)#define UNICODE #endif#include <tchar.h> #include <windows.h>/* Declare Windows procedure */…...
Kafka(七)可靠性
目录 1 可靠的数据传递1.1 Kafka的可靠性保证1.2 复制1.3 Broker配置1.3.1 复制系数1.3.2 broker的位置分布1.3.3 不彻底的首领选举1.3.4 最少同步副本1.3.5 保持副本同步1.3.6 持久化到磁盘flush.messages9223372036854775807flush.ms9223372036854775807 1.2 在可靠的系统中使…...
Spring Data JPA入门到放弃
参考文档:SpringData JPA:一文带你搞懂 - 知乎 (zhihu.com) 一、 前言 1.1 概述 Java持久化技术是Java开发中的重要组成部分,它主要用于将对象数据持久化到数据库中,以及从数据库中查询和恢复对象数据。在Java持久化技术领域&a…...
MES系统数据采集的几种方式
生产制造执行MES系统具有能够帮助企业实现生产数据收集与分析、生产计划管理、生产过程监控等的功能板块,在这里小编就不一一介绍了,主要讲讲它的数据采集功能板块,可以说,数据采集是该系统进行数据统计与生产管理等后续工作的基础…...
铭文 LaunchPad 平台 Solmash 推出早鸟激励计划
为感谢用户对Solmash的支持,Solmash 特别推出“Solmash早鸟激励计划”,以回馈社区的早期参与者,这是专为已经参与Staking Pool或Honest Pool的用户推出的激励。 Solmash NFT激励 被列入早鸟计划的用户,可通过点击:sol…...
【前端规范】
1 前言 HTML 作为描述网页结构的超文本标记语言,一直有着广泛的应用。本文档的目标是使 HTML 代码风格保持一致,容易被理解和被维护。 2 代码风格 2.1 缩进与换行 [强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格 或 tab 字符…...
12、JVM高频面试题
1、JVM的主要组成部分有哪些 JVM主要分为下面几部分 类加载器:负责将字节码文件加载到内存中 运行时数据区:用于保存java程序运行过程中需要用到的数据和相关信息 执行引擎:字节码文件并不能直接交给底层操作系统去执行,因此需要…...
【Docker】Docker安装入门教程及基本使用
🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《Docker实战》。🎯🎯 &…...
语义解析:如何基于SQL去实现自然语言与机器智能连接的桥梁
🌈个人主页: Aileen_0v0 🔥热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 💫个人格言:"没有罗马,那就自己创造罗马~" 目录 语义解析 定义 作用 语义解析的应用场景 场景一: 场景二: 总结语…...
Java项目:117SpringBoot动漫论坛网站
博主主页:Java旅途 简介:分享计算机知识、学习路线、系统源码及教程 文末获取源码 117SpringBoot动漫论坛网站 一、项目介绍 动漫论坛网站是由SpringBootMybatis开发的,旅游网站分为前台和后台,前台为用户浏览,后台进…...
Jenkins基础篇--添加节点
节点介绍 Jenkins 拥有分布式构建(在 Jenkins 的配置中叫做节点),分布式构建能够让同一套代码在不同的环境(如:Windows 和 Linux 系统)中编译、测试等。 Jenkins 运行的主机在逻辑上是 master 节点,下图是主节点和从节点的关系。 添加节点 …...
【C++】手撕 list类(包含迭代器)
目录 1,list的介绍及使用 2,list_node 3,list_node() 3,list 4,list() 5,push_back(const T& x) 6,print() 7,_list_iterator 8,operator*() 9,…...
@Autowired 和 @Resource 的区别是什么?
Java面试题目录 Autowired 和 Resource 的区别是什么? Autowired 是 Spring 提供的注解。默认的注入方式为byType(根据类型进行匹配)。 Resource 是 JDK 提供的注解。默认注入方式为 byName(根据名称进行匹配)。 当一…...
栈和排序.
给你一个1->n的排列和一个栈,入栈顺序给定 你要在不打乱入栈顺序的情况下,对数组进行从大到小排序 当无法完全排序时,请输出字典序最大的出栈序列 输入 第一行一个数n 第二行n个数,表示入栈的顺序,用空格隔开&…...
springboot 多数据源怎么配置在控制台的sql打印日志
程序员的公众号:源1024,获取更多资料,无加密无套路! 最近整理了一波电子书籍资料,包含《Effective Java中文版 第2版》《深入JAVA虚拟机》,《重构改善既有代码设计》,《MySQL高性能-第3版》&…...
【WinForms 窗体】常见的“陷阱”
当涉及到 WinForms 窗体编程时,我们可能会遇到一些常见的问题。在本篇博客中,我将为你提供一些常见问题的解决方案。 跨线程访问控件 在 WinForms 中,当在非UI线程上执行操作并尝试访问 UI 控件时,会引发跨线程访问异常。为了解决…...
Android readelf 工具查找函数符号
ELF(Executable and Linkable Format)是一种执行文件和可链接文件的格式。它是一种通用的二进制文件格式,用于在各种操作系统中存储可执行程序、共享库和内核模块。 Android 开发当中的 so 库本质上就是一种特殊类型的 ELF 文件,…...
MySQL-索引回顾
索引是面试高频问答题,参考百度/CSDN/尚硅谷/黑马程序员/阿里云开发者社区,决定将索引知识回顾一下,忘记时,点开即可,时刻保持更新,事不宜迟,即刻享用。 索引概述 索引(index&#…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
ZYNQ学习记录FPGA(一)ZYNQ简介
一、知识准备 1.一些术语,缩写和概念: 1)ZYNQ全称:ZYNQ7000 All Pgrammable SoC 2)SoC:system on chips(片上系统),对比集成电路的SoB(system on board) 3)ARM:处理器…...
从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...
