文章目录 前言正文一、项目简介二、核心代码2.1 pom.xml 依赖配置2.2 ExcelHeadMapFactory2.3 ExcelDataLinkedHashMap2.4 自定义注解 ExcelExportBean2.5 自定义注解 ExcelColumnTitle2.6 建造器接口 Builder2.7 表格工具类 ExcelUtils2.8 GsonUtil2.9 模版类 ExportDynamicColumnTemplate2.10 模版建造器 ExportDynamicColumnTemplateBuilder 三、控制器&调试Bean的定义3.1 StudentDemo3.2 NameAndFactoryDemo3.3 控制器 ExcelDemoController 四、启动类五、测试 前言 关于万能导出,前一阵子写过一个,功能是实现了的。
就是在使用时,感觉如果需要导出的页面比较多,那就会出现比较多的重复代码。就想着优化+简化一下,能够更方便的使用。
原版代码仓库和这一版的代码仓库相同:
https://gitee.com/fengsoshuai/excel-demo
原版中额外增加了转换器,枚举转换等功能,但是总觉得会让整体功能变复杂,所以在这一版中就去掉了。如果有兴趣看看的话,可以切换到master分支查看。
简化升级的这一版的代码分支是:simple-dynamic-column-export
正文 一、项目简介 本次简化升级,本着对使用者友好的目的去实现的。
另外,本文会粘贴全部代码!!
在使用上的简化体现在真正导出时,只需要几行代码,就能实现功能。可以让你更加专注于业务参数的组装。而且代码比较简洁。
举个例子:
@GetMapping("/exportDy") public String exportDy(@RequestParam("table") List<String> table, HttpServletResponse response) throws IOException { // 构造导出模版 ExportDynamicColumnTemplate<StudentDemo> dynamicColumnTemplate = new ExportDynamicColumnTemplateBuilder<>(StudentDemo.class) .columnNameList(table) .build(); // 制造假数据 dynamicColumnTemplate.appendExportDataList(studentDemos()); // 转换为excel的字节数组 byte[] bytes = dynamicColumnTemplate.toExcelByteArray(); // 响应到web String fileName = System.
function changeEnvMap(url) {
var loader99 = new THREE.RGBELoader();
loader99.load(url, function (texture) {
texture.encoding = THREE.RGBEEncoding;
texture.minFilter = THREE.NearestFilter;
texture.magFilter = THREE.NearestFilter;
texture.flipY = true;
var cubeGenerator = new THREE.EquirectangularToCubeGenerator(texture, { resolution: 1024 });
cubeGenerator.update(renderer);
var pmremGenerator = new THREE.PMREMGenerator(cubeGenerator.renderTarget.texture);
pmremGenerator.update(renderer);
var pmremCubeUVPacker = new THREE.PMREMCubeUVPacker(pmremGenerator.cubeLods);
pmremCubeUVPacker.update(renderer);
// var envMap = pmremCubeUVPacker.CubeUVRenderTarget.texture;
pmremGenerator.dispose();
pmremCubeUVPacker.dispose();
scene.environment = cubeGenerator.renderTarget;
scene.background = cubeGenerator.renderTarget;
});
}
可以支持多个不同Arm硬件的在线编辑器。支持单步调试、设置断点。
CPUlator Computer System Simulator
常用软件需求规格说明书模板
完整版 开发较大的软件或者需求时可以采用下面的模板:ISO2006模板
参考示例
示例1
敏捷开发 若采用敏捷开发的方式迭代,可以使用本文绑定的资源【软件需求规格说明书】。见文档最上方
遇到的问题:
当在 notepad++ 里复制了如下 xml 内容:
</DeployMetadata> <Version>1111</Version> <BOSVersion>1.0</BOSVersion> <BizunitId>222</BizunitId> </DeployMetadata> 然后粘贴到 IDEA 中时变成了:
</DeployMetadata> <Version>1111</Version> <BOSVersion>1.0</BOSVersion> <BizunitId>222</BizunitId> </DeployMetadata> 可以发现原来的空格缩进是 2 个,现在变成了 4 个 。
这还只是复制了几行代码,如果复制很长的 xml 或代码到 IDEA 中,势必会导致所有缩进都增加,导致代码变乱,如果通过 git 提交上去,会造成版本管理不便,即使你没改动的代码,提交记录上也会显示多余的空格缩进。
解决办法:
idea 中右下角点击 spaces ,选择 Configure Indents for XML…
在弹出的设置窗口将 Indent 缩进、Continuation Indent 连续缩进 都改成 2
设置好后重新复制代码到 idea 中就不会有多余的缩进空格了。
权限详解 1、Linux系统上对文件的权限有着严格的控制,如果想对某个文件执行操作,必须具有对应 的权限方可执行成功。
2、Linux下文件的权限类型一般包括读,写,执行。对应字母为 r、w、x 、等
3、Linux下权限的粒度有 拥有者 、群组 、其它组 三种。每个文件都可以针对三个粒度,设 置不同的rwx(读写执行)权限。通常情况下,一个文件只能归属于一个用户和组, 如果其 它的用户想有这个文件的权限,则可以将该用户加入具备权限的群组,一个用户可以同 时归属于多个组。
4、Linux文件的三种特殊权限分别是:suid权限、sgid权限、sticky权限;其中suid权限作用 于文件属主,sgid权限作用于属组上,sticky权限作用于other其他上。
Linux通常使用chmod命令对文件的权限进行设置和修改。
一、chmod使用 一般使用格式如下: chmod [可选项] <mode> <file...> 可选项为: 可选参数 mode为: 对应需要添加的权限 file: 添加权限的文件 参数说明: -c, --changes like verbose but report only when a change is made(大概意思就是若 该档案权限确实已经更改,才显示其更改动作) -f, --silent, --quiet suppress most error messages(若该文件权限无法被更改也不要显示错误讯 息) -v, --verbose output a diagnostic for every file processed (显示权限变更情况) --no-preserve-root do not treat '/' specially (the default) --preserve-root fail to operate recursively on '/' --reference=RFILE use RFILE's mode instead of MODE values -R, --recursive change files and directories recursively (递归地更改文件和目录) --help 显示此帮助信息并退出 --version 显示版本信息并退出 [mode] 权限设定字串,详细格式如下 : [ugoa][[+-=][rwxX] 其中 [u 、g、o、a]释义: u 表示所有者, g 表示所属组(group)者, o 表示其他以外的人, a 表示所有(包含上面三者)。 [+、-、=]释义: + 表示增加权限, - 表示取消权限, = 表示唯一设定权限。 [rwxX] r 表示可读取, w 表示可写入, x 表示可执行, X 表示只有当该档案是个子目录或者该档案已经被设定过为可执行。 [file.
什么是闭包? 闭包的意思其实就是在一个函数内部定义另一个函数(函数嵌套函数),并返回这个内部函数。这样,内部函数就形成了一个闭包,可以访问外部函数的变量和参数。
function outFunction(){ let outValue = "这是一个闭包"; function innerFunction(){ console.log(outValue); } return innerFunction; } const closure = outFunction(); closure(); // 输出 "这是一个闭包" 在前端开发中,主要有五大作用
保护变量 闭包可以用于保护变量,让他在外部无法直接访问或者修改。通过闭包,我们可以创建私有变量,只能通过内部函数来访问和修改。
function creatCounter(){ let count = 0; return { increment: function(){ count++; }, decrement: function(){ count--; }, getCount: function(){ return count; } } } const counter = creatCounter(); console.log(counter.getCount()); // 0 counter.increment(); counter.increment(); console.log(counter.getCount()); // 2 counter.decrement(); console.log(counter.getCount()); // 1 数据封装 闭包可以用于数据封装,通过创建私有变量和公共方法,实现对数据的封装和访问。
function createPerson(name,age){ let _name = name; let _age = age; return { getName: function(){ return _name; }, getAge: function(){ return _age; }, setName: function(newValue){ _name = newValue; }, setAge: function(newValue){ _age = newValue; } } } const person = createPerson("
目录 1 创建工程3 配置文件4 静态资源 之前我们已经学习的Spring、SpringMVC、Mabatis、Maven,详细讲解了Spring、SpringMVC、Mabatis整合SSM的方案和案例,上一节我们学习了SpringBoot的开发步骤、工程构建方法以及工程的快速启动,从这一节开始,我们开始学习SpringBoot配置文件。接下来,我们逐步开始学习,本教程所有示例均基于Maven实现,如果您对Maven还很陌生,请移步本人的博文《如何在windows11下安装Maven并配置以及 IDEA配置Maven环境》
SpringBoot 到这就已经学习完毕,接下来我们将学习 SSM 时做的三大框架整合的案例用 SpringBoot 来实现一下。我们完成这个案例基本是将之前做的拷贝过来,修改成 SpringBoot 的即可,主要从以下几部分完成
pom.xml
配置起步依赖,必要的资源坐标(druid)application.yml
设置数据源、端口等配置类
全部删除dao
设置@Mapper测试类页面
放置在resources目录下的static目录中 1 创建工程 创建 SpringBoot 工程,在创建工程时需要勾选 web 、 mysql 、 mybatis ,工程目录结构如下
由于我们工程中使用到了 Druid ,所以需要导入 Druid 的坐标
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> 2 代码拷贝
将 springmvc_11_page 工程中的 java 代码及测试代码连同包拷贝到 springboot_09_ssm 工程,按照下图进行拷贝
需要修改的内容如下:
Springmvc_11_page 中 config 包下的是配置类,而 SpringBoot 工程不需要这些配置类,所以这些可以直接删除dao 包下的接口上在拷贝到 springboot_09-ssm 工程中需要在接口中添加 @Mapper 注解BookServiceTest 测试需要改成 SpringBoot 整合 junit 的 @SpringBootTest public class BookServiceTest { @Autowired private BookService bookService; @Test public void testGetById(){ Book book = bookService.
//获取start--->end的向量
function rotateSpecifiedAxis(mesh:THREE.Mesh){
let vertices = [];
for (let i = 0; i < mesh.geometry.attributes.position.array.length; i += 3) {
vertices.push(new THREE.Vector3(mesh.geometry.attributes.position.array[i], mesh.geometry.attributes.position.array[i + 1], mesh.geometry.attributes.position.array[i + 2]));
}
let box = new THREE.Box3().setFromObject(mesh)
let center = new THREE.Vector3()
box.getCenter(center);
// 此处定义指定轴(起点----->终点)
let axis = new THREE.Vector3(this.m_vEnd.x, this.m_vEnd.y, this.m_vEnd.z).sub(new THREE.Vector3(this.m_vStart.x, this.m_vStart.y, this.m_vStart.z)).normalize();
//将所有点绕start--->end的向量旋转90度
vertices.forEach((item, index) => {
item.applyMatrix4(new THREE.Matrix4().makeTranslation(-center.x, 0, -center.z));
item = item.applyAxisAngle(axis, Math.PI / 2);
})
}
这个问题也是我今天突然偶尔遇到的,当时没在意,项目打开之后又关闭,后来很久才又打开,发现项目明明有git版本控制的,咋突然开发工具右下角没有标识了,然后检查了一下git配置还报错了。
其实从图上我们可以看出来一些问题,他意思是说不能执行git命令,在安全模式上。我顿时豁然开朗,好像当初打开项目的时候,Idea总是会提示弹出一个窗口,让我们选按钮,我当时可能没注意,就点了中间那个Peview in Safe Mode 意思就是在安全模式下查看。而我们正常要选第一个Trust Project 意思是 信任项目。
解决方法 那如何解决这个问题呢,既然进入了安全模式了,那我们只要退出安全模式应该就可以了。其实解决方法也很简单,你们按照我下面这些步骤来就能解决。
在 IntelliJ IDEA 中取消安全模式(safe mode)的方法如下:
打开 IntelliJ IDEA。点击菜单栏的 “File” 或者 “File” 图标,选择 “Exit Safe Mode”。 如果你使用的是最新版本的 IntelliJ IDEA,直接随便去项目中点击任何一个文件,然后观察右上角是否有这一行字跳出来,如图所示。
直接点击Trust Project 就完事,IntelliJ IDEA会重新构建就正常了。
需要注意的是,安全模式主要用于解决某些特定的问题,例如插件冲突、配置文件损坏等。在正常情况下,我们并不需要手动退出安全模式。如果你遇到了需要退出安全模式的情况,可以按照上述方法进行操作。
在数字时代,了解和分析网站流量至关重要。无论是新手网站所有者还是资深市场分析师,掌握如何解读网站的PV、UV和IP等指标对于评估网站表现、优化用户体验和制定有效市场策略都是必不可少的。以下是对这三个关键指标的详细介绍。
文章目录 1. PV(Page View)- 页面浏览量2. UV(Unique Visitor)- 独立访客3. IP(Internet Protocol Address)- 网络协议地址结语 1. PV(Page View)- 页面浏览量 定义: PV代表页面浏览量或点击量,它计算了一个特定页面在一定时间内被访问的次数。
重要性: PV的高低直接反映了网站内容的吸引力和用户活跃程度。通过分析PV,可以了解哪些内容最受欢迎,哪些页面需要改进,从而做出相应的调整和优化。
注意点: 虽然高PV通常被视为积极的指标,但如果大量访问是由自动刷新或单一用户的频繁点击造成的,那么它可能并不代表真实有效的用户参与。因此,PV应与其他指标如UV结合起来看。
2. UV(Unique Visitor)- 独立访客 定义: UV指在一定时间范围内访问网站的独立访客数,通常通过跟踪cookies或用户ID来识别。
重要性: UV是衡量网站覆盖面和吸引新用户能力的重要指标。与PV相比,UV可以提供更准确的用户数量估计,帮助你了解实际的用户基数和市场覆盖范围。
注意点: 由于用户可能会更换设备或删除cookies,UV计算可能不完全精确。此外,一个UV可能浏览多个页面产生多个PV,因此UV和PV应该一起分析,以获得更全面的网站使用情况。
3. IP(Internet Protocol Address)- 网络协议地址 定义: 每个上网的设备都有一个独一无二的IP地址,网站通过统计不同的IP地址来了解其服务的覆盖范围和访问者的地理分布。
重要性: IP统计不仅可以帮助你了解网站的地理覆盖情况,还可以监测和防范异常流量,如DDoS攻击等。
注意点: 由于多个用户可能共享同一个IP地址(例如在同一个家庭或公司内),IP数并不完全等同于用户数。此外,IP地址可能会被隐藏或更改,因此它只能作为参考而非绝对精确的指标。
结语 PV、UV和IP是网站数据分析中的基础,但它们只是众多指标中的一部分。有效的数据分析需要综合多种指标,并结合网站的具体情况和目标进行。理解这些基本概念是走向更深入分析的第一步,随着经验的积累,你将能够更准确地解读这些数据,更好地推动网站的成长和成功。
文献计量学是指用数学和统计学的方法,定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体,注重量化的综合性知识体系。特别是,信息可视化技术手段和方法的运用,可直观的展示主题的研究发展历程、研究现状、研究热点和发展态势。Citespace和vosviewer是使用最广泛的文献信息可视化软件工具,在理工、经管、法学、教育、农学、文史、医学、艺术等学科中普遍应用,发文量逐年显著上升。本课程将采用理论与实践相结合,通过文献计量学讲解、高效选题、数据库检索数据下载、软件使用等八个专题详细讲解,让学员系统全面的掌握文献计量学的基本理论和知识;熟练掌握Citespace和vosviewer及R语言文献可视化分析技术;最终实现从主题确定、数据分析绘图、文章框架与写作,全流程掌握一篇文献信息可视化分析报告(论文)的思路逻辑与技术方法。
专题一
文献计量学方法与应用简介
1.文献计量学方法基本介绍
2.与其他综述方法区别联系
3.各学科领域应用趋势近况
4.主流分析软件优缺点对比
专题二
主题确定、检索与数据采集
1.热点主题高效选择方法
2.目标主题可行性预判
3.CNKI数据库检索式构建
4.CNKI数据导出方法与注意事项
5.WOS数据库检索式构建
6.WOS数据导出与注意事项
专题三
VOSviewer可视化绘图精讲
【案例+实践】
1.Vosviewer界面与主要概念简介
2.WOS与CNKI数据导入
3.共被引网络图绘制与解读关键
4.叠加网络图绘制与解读关键
5.密度图绘制与解读关键
6.关键词合并方法与注意事项
7.VOSviewer与Pajek耦合展示
专题四
Citespace可视化绘图精讲
【案例+实践】
1.CiteSpace版面与主要概念介绍
2.WOS与CNKI数据导入、清洗方法
3.学科分布图绘制参数选择与解读
4.共现网络图绘制参数选择与解读
5.聚类图绘制参数选择与解读
6.突现图绘制参数选择与解读
7.时间线图绘制参数选择与解读
部分结果展示
专题五
R语言文献计量学绘图分析
【案例+实践】
1.R包安装调用、数据加载与过滤
2.发文趋势及引用分析与解读
3.文献来源分析与解读
4.合作网络分析与解读
5.文献分析与解读
6.关键词分析与解读
7.国家出版密度及合作分析与解读
部分结果展示
专题六
论文写作
1 典型结构模式剖析
2 软件搭配组合技巧
3 图表搭配组图策略
4 定向文献参考套路
5 模块化写作思路
专题七
论文投稿
1 期刊选择方法
2 投稿前准备工作
3 投稿过程注意事项
4 文献计量学常见审稿意见
node-red-contrib-amqp节点使用 一、简介1.1 什么是AMQP协议?1.2 什么是RabbitMQ? -> 开源的AMQP协议实现1.3 RabbitMQ的WEB管理界面介绍1.3 如何实现RabbitMQ的数据采集? -> node-red 二、node-red-contrib-amqp节点安装与使用教程2.1 节点安装2.2 节点使用2.2.1 amqp-broker节点2.2.2 amqp-in节点2.2.3 amqp-in-manual-ack节点2.2.4 amqp-out节点 回到目录
一、简介 1.1 什么是AMQP协议? AMQP,即 Advanced Message Queuing Protocol(高级消息队列协议),是一个网络协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。
AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP协议更多用在企业系统内对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。
详细内容参考链接:RabbitMQ系列四 AMQP协议介绍
回到目录
1.2 什么是RabbitMQ? -> 开源的AMQP协议实现 RabbitMQ是一个开源的AMQP协议实现,是在AMQP基础上完整的,可复用的企业消息系统。学习参考链接如下:
rabbitMQ官网RabbitMQ 详解:环境搭建教程 1.3 RabbitMQ的WEB管理界面介绍 一、总界面
connections:无论生产者还是消费者,都需要与RabbirMQ建立连接后才可以完成消息的生产和消费,在这里可以查看连接情况。channels:通道,建立连接后,会形成通道,以消息的投递获取以来通道。Excahnges:较平缓及,用来实现消息的路由。Queues:队列,即消息队列,消息存放在队列中,等待小品非,消费后被移除队列。 二、获取AMQP协议端口
三、查看交换机和路由
回到目录
1.3 如何实现RabbitMQ的数据采集? -> node-red 使用node-red的node-red-contrib-amqp节点,连接到RabbitMQ服务器(AMQP),以使用路由键从某个主题获取一些消息,实现客户端与消息中间件数据的传递。
二、node-red-contrib-amqp节点安装与使用教程 2.1 节点安装 node-red安装节点@meowwolf/node-red-contrib-amqp ,基于AMQP协议,实现客户端与消息中间件数据的传递。
回到目录
2.2 节点使用 2.2.1 amqp-broker节点 amqp-broker节点是指“AMQP消息代理器”,对应一个RabbitMQ实例,是一种中间件,用于接收、存储和转发消息。
这里的端口查看,请转至上节《1.3 RabbitMQ的WEB管理界面介绍》
2.2.2 amqp-in节点 该节点能连接到AMQP代理并获取消息,已msg.payload的形式输出,输出格式如下:
节点使用说明如下:
其中Exchange Info(交换信息)需要根据RabbitMQ中的实际情况进行配置:
type:指的是AMQP的消息路由方式,定义了消息如何从一个发送到AMQP消息代理(broker)的交换机(exchange)路由到一个或多个队列。有topic、direct、fanout和headers四种类型。 以下是这四种类型的简要说明:
object.children.forEach(ele=>{
// 创建线框几何体
var edges = new THREE.EdgesGeometry(ele.geometry); // 使用网格的几何体创建线框几何体
// 设置线框的材质
var lineMaterial = new THREE.LineBasicMaterial({color: 0xffffff}); // 设置线框颜色
var lineSegments = new THREE.LineSegments(edges, lineMaterial); // 创建线框对象
lineSegments.material.transparent=true
lineSegments.material.opacity=0.5
ele.updateMatrixWorld(true); // 重点!!!
lineSegments.applyMatrix(ele.matrixWorld); // 重点!!!
lineSegments.name='xiankuang'
scene3D.add(lineSegments)
})
删除以上生成的线框:
for(let i=0;i<scene3D.children.length;i++){
if(scene3D.children[i].name=='xiankuang'){
scene3D.remove(scene3D.children[i])
i--;
}
}
// 字符串转文档方法
function xmlStr2XmlObj(strXML) {
var xmlObj = {};
if (document.all) {
var xmlDom = new ActiveXObject("Microsoft.XMLDOM");
xmlDom.loadXML(strXML);
xmlObj = xmlDom;
} else {
xmlObj = new DOMParser().parseFromString(strXML, "text/xml");
}
return xmlObj;
}
// 转完文档就可以进行方便操作,比如清除文档中的一部分。
// 例如:清除家具字段
strXML = xmlStr2XmlObj(strXML);
$(strXML).find('Furniture3D').remove()
// 若要替换家具字段
// 替换家具数据操作
if(mHouseClass.mFurnitureArray.length>0){
//家具数据
let new_Furniture3D = mHouseClass.OnSaveFurniture_XML();
$(strXML).find('PillarJson').before(new_Furniture3D)
}
// 此时strXML还是文档,现在转字符串
strXML = strXML.documentElement.innerHTML;
//最终strXML是一个字符串
<template> <div class="small-user-wrapper"> <!-- 搜索 --> <el-card class="box-card"> <div class="filter-container"> <el-form :model="searchInfo" label-width="120px"> <Row> <Col :xs="24" :lg="6"> <el-form-item label="用户评价:"> <el-select v-model="searchInfo.recommend_type" style="width:100%;" placeholder="请选择用户评价状态" clearable> <el-option label="好评" :value="1"></el-option> <el-option label="差评" :value="2"></el-option> </el-select> </el-form-item> </Col> </Row> <el-row type="flex" justify="end" style="margin-bottom:10px;align-items: center;"> <el-button type="primary" icon="el-icon-search" style="margin-right: 10px" @click="search">搜索</el-button> <el-button type="dange" icon="el-icon-refresh" style="margin-right: 10px" @click="reset">重置</el-button> <!-- <el-button type="primary" style="margin-right: 10px">导出</el-button> --> <!-- <div class="screen" @click="more=!more">{{more?'收起':'更多'}}筛选<i :class="more?'el-icon-arrow-up':'el-icon-arrow-down'"></i></div> --> </el-row> </el-form> </div> </el-card> <el-card class="box-card" style="
<template> <div class="small-user-wrapper"> <!-- 搜索 --> <el-card class="box-card"> <div class="filter-container"> <el-form :model="searchInfo" label-width="120px"> <Row> <Col :xs="24" :lg="6"> <el-form-item label="规则名称:"> <el-input v-model="searchInfo.title" placeholder="请输入规则名称" style="width: 200px; margin-right: 10px" @keyup.enter.native="search"> </el-input> </el-form-item> </Col> </Row> <el-row type="flex" justify="end" style="margin-bottom:10px;align-items: center;"> <el-button type="primary" icon="el-icon-search" style="margin-right: 10px" @click="search">搜索</el-button> <el-button type="dange" icon="el-icon-refresh" style="margin-right: 10px" @click="reset">重置</el-button> <!-- <el-button type="primary" style="margin-right: 10px">导出</el-button> --> <!-- <el-button type="primary" icon="el-icon-refresh" style="margin-right: 10px">刷新状态</el-button> --> <!-- <div class="screen" @click="more=!more">{{more?'收起':'更多'}}筛选<i :class="more?'el-icon-arrow-up':'el-icon-arrow-down'"></i></div> --> </el-row> </el-form> </div> </el-card> <el-card class="
创建一个SpringBoot项目,你会发现只有启动类的上方存在一个注解@SpringBootApplication,继续点开该注解你会发现它是一个复合注解,包含@ComponentScan、@SpringBootConfiguration、@EnableAutoConfiguration等注解,其中@EnableAutoConfiguration注解就是用于开启自动配置的注解。
继续点击@EnableAutoConfiguration注解,你会发现@EnableAutoConfiguration注解中使用了@Import注解,该注解引用了AutoConfigurationImportSelector,AutoConfigurationImportSelector组件提供了getAutoConfigurationEntry(AnnotationMetadata annotationMetadata)的方法用于获取所有的配置类信息,并对无用的配置类进行过滤,源码如下:
通过源码能看到,getAutoConfigurationEntry()方法中是通过getCandidateConfigurations(annotationMetadata, attributes)来获取所有的配置类,而该方法实际上是调用了SpringFactoriesLoader类中的loadFactoryNames和loadspringFactories方法来读取META-INF/spring.factories文件,从META-INF/spring.factories文件中读取所有配置类信息
题外话:所以点了这么多层,最后干活的是SpringFactoriesLoader中的laodSpringFactories方法。。。。。附源码。
我画了一张图,可能看不太清,可以下载之后放大看。
总结:Spring Boot的自动配置原理,@SpringBootApplication的注解中包含了@EnableAutoConfiguration注解,该注解引入了@Import注解,Spring IOC容器在启动时会解析@Import注解,而@Import注解又引入了AutoConfigurationImportSelector组件,该组件会调用SpringFactoriesLoader中的loadFactorNames方法,而loadFactorNames方法又会调用loadSpringFactories方法来读取META-INF下的spring.factories文件中的配置类信息并返回。AutoConfigurationImportSelector组件在获取到所有的配置类信息之后,会通过@Condition注解过滤无效的配置类。
项目介绍: 飞书信息发送服务是指将飞书信息发送服务部署到一个Linux服务器上。飞书是一款企业级的即时通讯和协作工具,支持发送消息给飞书的功能。通过部署飞书信息发送服务,可以方便内网发送信息给外网飞书。
项目代码结构展示: 文件结构解释: common文件夹保存了一些基础运行文件。
api.py通过调用飞书开放平台的API获取租户访问令牌,其中调用了飞书的url接口。
logs.py将日志数据保存到文件夹logs中。
send_message.py实现使用飞书开放平台的API发送消息给指定用户。
logs文件夹保存的是消息传递过程中产生的日志信息。
other文件夹保存有可转换文件的部分程序,供后续开发使用。
static文件夹保存有html文件需要调用的css、js和json文件等配置文件。
templates文件夹保存有index.html文件,即网页运行文件。
app.py文件是整个项目的运行文件,实现了一个简单的web应用程序,用户可以通过表单提交消息,并将消息发送给另一个模块进行处理。同时,在后台记录了用户的IP地址、ID、消息和用户名等信息。 项目代码解释: 1. api.py代码解释: ''' 该代码的作用是使用飞书开放平台的 API 获取应用的访问令牌(tenant_access_token),并将其打印出来。 该代码通过发送HTTP POST请求,获取飞书应用的访问令牌,并将结果打印出来,以便后续使用该令牌来访问飞书开放平台的其他API。 ''' # 导入requests模块。 import requests # 飞书信息传入接口 # 定义了请求的URL,该URL用于获取应用的访问令牌。 url = 'https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal' # 定义了请求的头部,指定Content-Type为application/json。 headers = { 'Content-Type': 'application/json' } # 定义了请求的数据,包括应用的app_id和app_secret。 # 得从飞书集成平台上创建一个飞书服务,从而获得其中的参数 data = { # 请求参数(从飞书内部app获得) "app_id": "cli_a5cb1xxxxxxxxxxxxx", "app_secret": "qNFmmFTQqexxxxxxxxxxxxxxxxxxxxxxx" } # 发送POST请求,将URL、头部和数据传递给requests.post()函数,并将返回的响应对象保存在response变量中。 response = requests.post(url, headers=headers, json=data) # 检查响应的状态码,如果状态码为200,则表示请求成功,继续执行下一步;否则打印请求失败的提示信息。 if response.status_code == 200: # 请求成功 # 将响应的内容解析为JSON格式,保存在result变量中。 result = response.
本文为官方文档直译版本。原文链接
Spring Boot Web中文文档 引言Servlet Web ApplicationsSpring Web MVC FrameworkSpring MVC 自动配置Spring MVC 转换服务HttpMessageConvertersMessageCodesResolver静态内容欢迎页面自定义图标路径匹配和内容协商ConfigurableWebBindingInitializer模板引擎错误处理自定义错误页面在 Spring MVC 之外映射错误页面WAR 部署中的错误处理 CORS 支持 JAX-RS 和 Jersey嵌入式 Servlet 容器支持Servlets, Filters, 和 Listeners将 Servlet、Filters和Listeners注册为 Spring Bean 初始化 Servlet 上下文扫描Servlets, Filters, 和 listeners ServletWebServerApplicationContext自定义嵌入式 Servlet 容器SameSite Cookie字符编码程序自定义直接自定义 ConfigurableServletWebServerFactory JSP 的局限 Reactive Web ApplicationsSpring WebFlux FrameworkSpring WebFlux 自动配置Spring WebFlux 转换服务带有 HttpMessageReaders 和 HttpMessageWriters 的 HTTP 编解码器静态内容欢迎页面模板引擎错误处理自定义错误页面 Web Filters 嵌入式反应式服务器支持自定义反应式服务器程序自定义直接自定义 ConfigurableReactiveWebServerFactory 反应式服务器资源配置 优雅关机Spring SecurityMVC SecurityWebFlux SecurityOAuth2Client通用提供商的 OAuth2 客户端注册 资源服务器认证服务器 SAML 2.
文章目录 需求准备工作自定义复制策略编译代码 需求 使用MM2同步集群数据,topic名称不能变,默认的复制策略为:DefaultReplicationPolicy,这个策略会把同步至目标集群的topic都加上一个源集群别名的前缀,比如源集群别名为A,topic为:bi-log,该topic同步到目标集群后会变成:A.bi-log,为啥这么做呢,就是为了避免双向同步的场景出现死循环。
官方也给出了解释:
这是 MirrorMaker 2.0 中的默认行为,以避免在复杂的镜像拓扑中重写数据。 需要在复制流设计和主题管理方面小心自定义此项,以避免数据丢失。 可以通过对“replication.policy.class”使用自定义复制策略类来完成此操作,所以本文主要记录一下自定义复制策略的流程。
准备工作 下载源码
https://kafka.apache.org/downloads
kafka源码是使用Gradle编译的,需要安装Gradle,具体安装操作不赘述了,可以百度。
源码使用IDEA打开后,在connect模块下找到接口:org.apache.kafka.connect.mirror.ReplicationPolicy
自定义复制策略 ReplicationPolicy这个接口主要有几个方法:
formatRemoteTopic:重命名topic名称topicSource:根据topic获取source集群别名upstreamTopic:获取topic在source集群中的名称originalTopic:获取topic原始的名称(针对多次同步过程中,被重命名过多次的topic)isInternalTopic:判断是否为内部topic 根据我们的需求,自定义策略需要满足:
不重命名source集群中topic的名称能返回source集群别名 实现很简单,就是保证topic原封不动即可,完整代码如下:
package org.apache.kafka.connect.mirror; import org.apache.kafka.common.Configurable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Map; import java.util.regex.Pattern; /** * Defines remote topics like "us-west.topic1". The separator is customizable and defaults to a period. */ public class CustomReplicationPolicy implements ReplicationPolicy, Configurable { // In order to work with various metrics stores, we allow custom separators.
大家好!今天我将用一种二大爷也能听懂的方式来分享一个实操干货——如何使用Stable Diffusion在10秒钟内将您的普通照片变身为有趣的卡通头像。不论您是社交媒体上的头像达人,还是仅仅想为自己的数字身份增添一些个性,这篇教程都将是您的不二选择。现在,让我们一起迈入Stable Diffusion的奇妙世界,发掘其在个性化创作上的无限可能性。
认识Stable Diffusion Stable Diffusion(简称SD)是一种强大的AI图像生成工具,它能够根据您的描述生成几乎任何类型的图像。从梦幻般的风景到精确的产品设计,SD都能轻松应对。特别是在个性化头像制作上,SD展示了其独特的魅力和高效性。您只需提供一张照片和简单的描述,SD便能在瞬间为您带来惊喜。
头像制作案例 想象一下,以前制作一个独一无二的头像或壁纸,您可能需要花费大量时间和金钱去请人定制。但现在,借助SD,您可以轻松定制属于自己的二次元头像、盲盒模型或个性壁纸。这不仅极大地节省了时间和成本,还为您提供了一个展示个性和创造力的平台。
-怎样?
-动心了么?
-你可能会问难么?
-难!?
-除非你想成为SD的大师.
-咱们需要的是什么?
-满足我们的日常需求.
-这个就一点也不难了.
-因为从今天开始我会抛弃那些繁琐难懂的参数讲解和教学
-我只用最简单的话语告诉你,怎么想,怎么做.
-我保证连二大爷都能听得懂,做得到.
-因为我觉得工具是拿来用的,只有用的顺手你才会有去精通的动力.
-学会一堆的理论,不如上手就能用.
-所以我们的口号就是:非名山不留僧住,是真佛直说家常.
-我的教程不会像那些技术大神一样拆解每一个参数的意义.
-我只会告诉你简单几步就能实现你想要的效果.
-Stable Diffusion原本就是这样简单!
问题1:把一个大象放到冰箱里需要几步?
答:3步
1、把冰箱门打开;
2、把大象放进去;
3、把冰箱门关上.
问题2:把一张头像图片改成卡通风格需要几步?
答:5步
1、选择SD卡通风格大模型
2、把SD的图生图打开;
3、上传图片;
4、按照步骤做一些简单的设置;
5、点击生成.
很多时候事情觉得难或者麻烦是因为,我们没有找到合适的思路.只要思路有了,你就有无限的创意,而不需要别人告诉你该怎么做.
例如:我要帮妹子把这张图转换成卡通头像
我只需要下面5步:
1.选一个卡通大模型:(按照图选则即可)
2.打开SD图生图选项卡
3.把妹子的图放到图生图中
4.调整参数:
妹子说:“怎么不像自己?”你就拉低一些数值,比如说.035
妹子说:“我想要再夸张一些.”你就拉高一些数值.
没什么难的,总之数值越小就越像原图,越大就越奔放.
帮大家跑一下从0.2-1.0不同重绘强度的图的视觉样子。
数值越大软件画图越精细.
不过也不能太大画蛇添足的故事,小时候还是听过的吧?
先保持默认跑几张看看
不知道是多少?
没事,会看宽窄吧?
如果是宽图就拉动上面这个,如果是窄图就拉动下面这个.
拉动的目的就只有一个让红框盖住下妹子的图片.
-(分叉刘海儿英文是什么?我不会……)
-我也不会!
没事,用这段给你写好的负面词汇.
EasyNegative, ng_deepnegative_v1_75t, badhandv4,(worst quality:2),
(low quality:2), (normal quality:2), lowres, ((monochrome)),
SpringAOP AOP为Aspect Oriented Programming的缩写,意为:面向切面编程。他是一种可以在不修改原来核心代码的情况侠给程序动态统一进行增强的一种技术
SpringAOP:批量对Spring容器中的bean方法做增强,并且这种增强不会与原来方法中的代码耦合
1.快速入门 1.1需求 要求让08_SpringAOP模块中service包下所有类的所有方法在调用前都输出:方法被调用了
1.2准备工作 第一步:引入依赖
<!--SpringIOC相关依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.1.9.RELEASE</version> </dependency> <!--AOP相关依赖--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.13</version> </dependency> 第二步:开启组件扫描
<context:component-scan base-package="com.sangeng"></context:component-scan> 第三步:相关bean注入容器中
@Service public class PhoneService { public void deleteAll(){ System.out.println("PhoneService中deleteAll的核心代码"); } } @Service public class UserService { public void deleteAll(){ System.out.println("UserService中deleteAll的核心代码"); } } 1.3实现AOP ①开启AOP注解支持 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--开启组件扫描--> <context:component-scan base-package="com.sangeng"></context:component-scan> <!--开启aop注解支持--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans> ②创建切面类 创建一个类,在类上加上@Component和@Aspect
目录 前言Anaconda介绍特点 一.下载安装包1.1 官网直接下载1.2 清华镜像网下载 二. 安装三.配置3.1 配置环境变量3.2 验证安装anaconda验证(安装多个python时)未添加环境变量的 python版本验证 3.3 anaconda设置更改conda源 四. 彻底卸载 前言 Anaconda介绍 Aanconda是基于conda的Python数据科学和机器学习开发平台
包括Conda、Python以及一大堆安装好的工具包,比如:numpy、pandas等
conda是一个开源的包、环境管理器,可以用于在同一个机器上安装不同版本的软件包及其依赖,并能够在不同的环境之间切换
总之,安装anaconda可以便于机器学习和数据分析。而且也不必再安装python,比较方便。
(通常情况下,不建议安装多个python的情况下再次安装Anaconda,容易导致版本混乱)
特点 优势:方便了Python数据科学和机器学习,一次安装,不用再一个一个下载第三方库
不足:软件较大,会造成功能冗余。
一.下载安装包 1.1 官网直接下载 下载地址
首先我们可以去anaconnda官网下载安装包,不过由于它是外国网站,所以下载速度很慢,而且时不时出现下载失败,所以不建议去官网下载安装包。
建议选择第二种方法下载
进入官网下载地址后出现界面,可以直接点击Download下载,也可以划到最下面选择版本(windows好像默认只有最新版)
1.2 清华镜像网下载 下载地址
在这里可以查看版本信息,选择比较新的并且符合自己操作系统的版本即可。
划到底部可以选择最新版本安装
点击下载链接后等待下载完毕
二. 安装 点击启动下载后的安装程序
下一步(Next)
同意协议(I Agree)
这里可以根据自己实际情况选择,如果本机有多个用户使用,可以选择All Users(后续操作需要管理员授权),否则直接选择默认(Just Me)即可。之后点击下一步
选择安装路径,最好不要装在C盘,点击Browse…,浏览路径并选中即可。然后接着下一步(Next)
这里需要注意一下,默认情况下第一个选框没有勾选。视自身情况选择
如果本机未安装python,可以勾选。这将自动把anaconda添加到系统环境变量,不用再手动添加了,比较方便。如果没有勾选,稍后需要手动将anaconda加入到环境变量。
如果已经安装了python,就不要勾选,否则原默认python会被更改为Anaconda自带的python,相当于原来的python不起作用了。如果想在命令行使用原来python,不要勾选它。
点击安装(Install)等待安装
这个可以不管,直接下一步就行。
这两个框可选(没必要勾选)
勾选再Finish,就会弹出两个浏览器窗口到官网查看相关产品信息
取消勾选再Finish即可结束安装。
在菜单位置可以直接找到相关的启动程序(不然自己去安装的文件里找比较麻烦)。建议鼠标右键并选择打开文件位置,把快捷方式拉到桌面方便以后进去。
三.配置 3.1 配置环境变量 (如果本机原来未安装python并且已勾选自动添加环境变量,这一步直接跳过即可)
注意如果不希望原来的python版本被覆盖,环境变量这一步直接跳过!
鼠标右键点击此电脑,打开属性
找到高级系统设置
点击环境变量
在系统变量中选择path双击进行修改
添加以下路径(根据自己的路径进行修改)
D:\anaconda\anaconda3 D:\anaconda\anaconda3\Library\mingw-w64\bin D:\anaconda\anaconda3\Library\usr\bin D:\anaconda\anaconda3\Library\bin D:\anaconda\anaconda3\Scripts 3.
这一决策不仅成为了科技新闻的头条,更引发了关于AI伦理与法律的深入讨论。据报道,字节跳动涉嫌使用GPT数据来优化其自家AI模型。这一事件突显了在AI技术发展的道路上,遵循规则和伦理的重要性。
在这个背景下,知识蒸馏技术显得尤为重要。它不仅是AI技术的一个关键分支,更是在合规和伦理框架内推进技术创新的典范。知识蒸馏允许我们在保护原始数据隐私的前提下,转移和应用AI模型中的关键知识。这种技术使得即使在严格的数据使用规范和法律约束下,我们也能有效地利用AI模型的强大能力。
因此,本文将深入探讨知识蒸馏技术的原理、应用和挑战,同时着重强调其在遵守现代AI伦理和法律规范中的作用。我们将首先了解知识蒸馏的基本概念,然后探讨其在各种场景下的实际应用,最后讨论在技术发展和规则遵守并行不悖的大背景下,知识蒸馏如何成为连接理论与实践的重要桥梁。
文章目录 当前挑战知识蒸馏技术什么是知识蒸馏?知识知识的多样性基于响应的知识基于特征的知识基于关系的知识 训练离线蒸馏在线蒸馏自蒸馏 架构设计的关键性知识蒸馏算法对抗蒸馏多教师蒸馏跨模态蒸馏其他蒸馏算法 应用领域1. 视觉2. 自然语言处理(NLP)3. 语音 结论附录:我们的AI服务 当前挑战 随着大规模机器学习和深度学习模型的应用日益广泛,我们面临着新的挑战。例如,GPT-3这样的模型在570GB的文本数据上进行训练,拥有高达1750亿个参数。虽然这些庞大的模型在推动技术发展方面发挥了重要作用,但将它们部署到实际应用中,尤其是边缘计算设备上,却是一项艰巨的任务。
数据科学的当前趋势主要集中在开发单一的大型模型或多模型组合,以在验证集上获得出色的表现。然而,这些验证集往往无法充分反映现实世界中的数据多样性。因此,尽管一些机器学习模型在精心策划的验证数据集上表现出色,但在实际应用中,面对真实测试数据时,它们往往难以满足性能、响应时间和处理能力的要求。
知识蒸馏技术 知识蒸馏技术为这些挑战提供了有效的解决方案。它通过从复杂的机器学习模型或多模型组合中提取关键知识,并将其转化为更小、更易于部署的单一模型,实现了在不显著降低性能的前提下应对这些挑战。这种方法不仅提高了模型的实用性,而且为深度学习的发展提供了新的视角。
博客内容概览
在本篇博客中,我将涵盖以下主题:
知识蒸馏的详细描述:包括其基本原理、训练方案和算法。知识蒸馏在不同领域的应用:深入探索其在图像、文本和音频深度学习中的实际应用。 什么是知识蒸馏? 知识蒸馏指的是将知识从一个庞大、复杂的模型或一组模型传递到一个更小、更简洁的模型的过程。这种小型模型能够在现实世界的限制条件下得到有效部署。本质上,它是一种模型压缩的形式。
在过去十年中,随着深度学习在语音识别、图像识别和自然语言处理等领域的成功应用,知识蒸馏技术在现实世界应用中变得越来越重要。
特别是在部署大型深度神经网络模型时,面对内存和计算能力有限的边缘设备,这种挑战尤为显著。模型压缩方法的提出和希顿(Hinton)及其同事对“知识蒸馏”框架的正式命名,标志着这一技术的重要进步。
如图1所示,知识蒸馏中的小型“student”模型学习模仿大型的“teacher”模型,并利用教师的知识实现相似或更高的准确率。在接下来的内容中,我将深入探讨知识蒸馏框架及其底层架构和机制。
知识 知识蒸馏技术是深度学习中一项革命性的进步,它包括三个核心要素:知识、蒸馏算法和师生架构。
知识的多样性 在神经网络领域,我们通常将“知识”定义为网络学习到的权重和偏差。在大型深度神经网络中,知识的来源异常丰富。例如,知识蒸馏中常用logits作为从教师模型提取知识的主要来源,但也有研究集中于利用中间层的权重或激活值。除此之外,其他知识形式还包括不同类型的激活、神经元间的关系,甚至是教师模型本身的参数。
我们可以将这些不同的知识形式归类为三种类型:
基于响应的知识(见图2)基于特征的知识基于关系的知识 下面,我将详细探讨这三种不同的知识来源及其在知识蒸馏中的应用。
基于响应的知识 如图2所示,基于响应的知识主要关注教师模型的最终输出层。学生模型的目标是模仿教师模型的预测。这一过程,如图3所示,可以通过一种称为蒸馏损失的特殊损失函数来实现,该函数量化了学生模型与教师模型logits之间的差异。在训练过程中,通过最小化这一损失,学生模型逐渐学会像教师模型那样进行预测。
在计算机视觉任务(例如图像分类)中,软目标(soft targets)承载了基于响应的知识。软目标代表了输出类别的概率分布,通常通过softmax函数来估计。软目标在知识蒸馏过程中的影响通过一个称为“温度”的参数来调节,这种基于软目标的知识蒸馏通常应用于监督学习环境中。
基于特征的知识 如图4所示,经过训练的教师模型在其中间层中捕获了丰富的数据知识,这对深度神经网络至关重要。这些中间层学会识别特定的特征,这种知识可以被用来训练学生模型。目标是使学生模型学习到与教师模型相同的特征激活。通过最小化两者特征激活之间的差异,蒸馏损失函数实现了这一目标。
基于关系的知识 如图5所示,除了来自神经网络输出层和中间层的知识,我们还可以利用捕捉特征图之间关系的知识来训练学生模型。这种形式的知识,被称为基于关系的知识,可以通过模型特征图之间的相关性、图形、相似度矩阵、特征嵌入,或者特征表示的概率分布来建模。
通过深入理解这些知识的不同形式和来源,我们能更有效地实现知识蒸馏,从而在保持模型性能的同时减小其规模和复杂度。
训练 知识蒸馏的实施涉及多种训练方法,主要分为三种类型:离线蒸馏、在线蒸馏和自蒸馏。这些方法的选择取决于教师模型与学生模型是否同时进行修改,如图6所示。
离线蒸馏 离线蒸馏是最为常见的知识蒸馏方法。这种方法涉及使用一个已预训练的教师模型来指导学生模型。具体过程如下:首先在训练数据集上预训练教师模型,然后将教师模型的知识转移到学生模型中。鉴于深度学习领域的最新进展,现在有许多开源的预训练神经网络模型可用作教师。由于其实施相对简单,离线蒸馏在深度学习领域中成为了一种成熟的技术。
在线蒸馏 与离线蒸馏不同的是,在线蒸馏中,教师和学生模型在一个端到端的训练过程中同时进行更新。这种方法特别适用于无法使用预训练模型的场景。在线蒸馏可以充分利用并行计算资源,使其成为一种效率较高的训练方法。
自蒸馏 自蒸馏是一种独特的训练方法,如图6所展示,它使用同一模型作为教师和学生。例如,可以使用神经网络深层的知识来训练其浅层。这种方法可以被视为在线蒸馏的一个特例,并可以通过多种方式实现,例如将教师模型早期的知识传递给学生模型的后期训练。
通过这三种不同的训练方法,知识蒸馏技术为深度学习模型提供了灵活性和高效性,使其在现代计算环境中更具适应性和实用性。
架构设计的关键性 在知识蒸馏领域,设计高效的学生-教师网络架构至关重要。由于通常存在教师模型(复杂)与学生模型(简单)间的模型容量差距,优化知识传递变得尤为重要。以下是一些常见的架构设计方法:
简化版教师模型:使用更少的层和更少的神经元。教师模型的量化版本:通过减少存储和计算需求来简化模型。具有高效基本操作的较小网络:优化了运算效率。具有优化全局网络架构的较小网络:更好地利用资源。与教师相同的模型:但在某些方面进行了简化或优化。 此外,利用神经架构搜索这样的最新技术,可以为特定教师模型设计最优的学生模型架构。
知识蒸馏算法 本部分将深入探讨用于将教师模型的知识转移给学生模型的各种算法。
对抗蒸馏 在生成对抗网络(GAN)的背景下发展起来的对抗学习,已被应用于知识蒸馏。这种方法涉及训练一个生成模型,以生成尽可能接近真实数据分布的合成数据样本,以及一个判别器模型,用于区分真实和合成数据样本。对抗蒸馏利用这一概念,旨在提升学生和教师模型在真实数据分布表示方面的能力。
对抗学习可用于训练生成模型,以获取合成训练数据样本,这些样本可直接使用或用于增强原始训练数据集。基于对抗学习的另一种蒸馏方法关注于训练判别器模型,该模型根据逻辑或特征图区分学生和教师模型的输出。这有助于学生更好地模仿教师。此外,还有一种在线蒸馏技术,其中学生和教师模型同时进行优化。
多教师蒸馏 多教师蒸馏策略下,学生模型从多个不同的教师模型获取知识。如图7所示,采用多个教师模型可以为学生模型提供多种类型的知识,这可能比单一教师模型提供的知识更有益。
多教师提供的知识可合并为所有模型的平均响应。通常,教师传递的知识类型基于逻辑和特征表示。正如之前讨论的,多个教师可以传递不同类型的知识。
跨模态蒸馏 跨模态蒸馏如图8所示,涉及一个在特定模态上训练的教师模型,其知识被提炼并传递到需要从不同模态获取知识的学生模型。当训练或测试期间缺乏特定模态的数据或标签时,跨模态蒸馏变得尤为重要。
这种方法在视觉领域尤为常见。例如,一个在带标签的图像数据上训练的教师模型的知识,可以用于提炼一个以无标签数据(如光流、文本或音频)为输入领域的学生模型。在这种情况下,教师模型的图像特征用于指导学生模型的训练。跨模态蒸馏对于视觉问答、图像描述等应用至关重要。
其他蒸馏算法 除了上述主要方法,还有几种其他蒸馏算法在知识蒸馏中有着重要应用:
基于图的蒸馏:使用图结构来捕捉数据内部的关系。基于注意力的蒸馏:从特征嵌入中通过注意力图传递知识。无数据蒸馏:在没有原始训练数据的情况下,使用合成数据进行训练。量化蒸馏:从高精度教师模型传递知识到低精度学生模型。终身蒸馏:将先前学到的知识积累并应用于未来的学习任务。基于神经架构搜索的蒸馏:寻找最适合的学生模型架构以优化学习过程。 这些方法的多样性使得知识蒸馏成为一种强大而灵活的工具,能够适应各种深度学习的应用场景。
由于网络、CPU资源等原因,读写分离的延迟不可避免。所以,在引入读写分离方案的时候,要优先考虑数据延迟对业务是否有影响。下面主要讨论对有影响的情况下,有哪些方式可以尽量减少影响。
延迟处理方案 主从延迟可以很小,也可能很大,这是我们无法控制的。如果只用选择一个方案来解决延迟问题,就要考虑到最极端的情况,势必会让方案的成本超出预期。所以,最好是根据业务的重要程度,选择不同的方案。
读主库 对于一致性要求高的地方,这是最简单的方式,读主库就没有数据延迟问题。所以,引入读写分离之后,一定要对业务进行合理的划分。在功能实现上,如果用的ShardingPhere框架,默认在事务里的查询会默认走主库,一般就是写库。打开spring.shardingsphere.props.sql-show=true 配置就能打印SQL在哪个库执行。
Actual SQL: master ::: Insert Into ... Actual SQL: slave0 ::: Select * From ... 等待几秒 大多数情况下,延迟时间在1秒之内。写入成功后,主动等待1秒后再查询,可以确保大多数情况能查到数据。这种方式实现简单,对业务侵入性低。看似很low,但能解决对一致性有要求的情景。当然,无脑等1秒在延迟很低的情况下,1秒就是白等。
判断GTID GTID全局事务ID是Mysql5.6引入,我们可以通过获取主库提交事务后的GTID,在从库里判断GTID是否已经执行。已经执行则代表主库的事务已经同步到从库。
先通过SHOW VARIABLES LIKE 'gtid_mode' 命令查看GTID是否开启,返回ON表示开启。
+---------------+-------+ | Variable_name | Value | +---------------+-------+ | gtid_mode | ON | +---------------+-------+ 未开启的话要在my.cnf配置文件里开启。
gtid_mode = ON enforce_gtid_consistency = ON 获取事务的GTID 在提交事务后,通过SHOW VARIABLES LIKE 'gtid_executed'; 或者SELECT @@GTID_EXECUTED; 查询到已经提交的事务ID集合,可能会返回ff782504-9b09-11ee-a4c3-0050568c4224:1-3 这样的格式,然后我们处理一下,获取最后一个事务IDff782504-9b09-11ee-a4c3-0050568c4224:3 。
从库判断事务是否同步 在从库通过*wait_for_executed_gtid_set*(gtid_set [, timeout]) 方法可以查询指定的事务ID是否已经执行成功,方法返回0表示已经执行;返回1表示执行超时;返回其他数值表示失败。
gtid_set是事务ID的集合,查询一个或多个事务可以用5f4cea4d-38b5-11ec-8814-0800272d6057:1,5f4cea4d-38b5-11ec-8814-0800272d6057:3 或连续的话用5f4cea4d-38b5-11ec-8814-0800272d6057:1-5这样的格式timeout是可选参数,可以设置方法执行的超时时间,单位是秒。不传的话用的是**slave_net_timeout** 变量的值,默认是60秒。 例如,我们执行select *wait_for_executed_gtid_set*('5f4cea4d-38b5-11ec-8814-0800272d6057:3', 1); 返回了0,我们就知道数据同步完成,就可以继续查询数据。如果返回非0,就直接查主库。
一:行业经历 测试行业爬模滚打7年,从点点点的功能测试到现在成为高级测试,工资也翻了几倍;个人觉得,测试的前景并不差,只要自己肯努力;我刚出来的时候是在鹅厂做外包的功能测试,天天点点点,很悠闲,点了两年,发觉这样下去会废,
二:不断学习 然后就开始学习python,java,学着搞自动化测试,不过说实话,自学的话很容易死在入门阶段,要有很强的自制力,后面学会了一些皮毛,跳槽去另外一家公司,平常比较好学,加班或者没什么项目做的时候都会自己看书,学敲代码,被领导赏识,派去总部核心技术团队学习了一个礼拜的ui自动化,是有专人带,然后回来就把公司app的自动化交给了我,这才算是真正入门自动化了,然后就开始自己琢磨,抄人家的框架,等等,做是做出来了,但是比较low,
三:跳槽学习新技术 后面又跳槽去了一家金融公司,专职做自动化,幸好到了这家公司,这里自动化的负责人是字节出来的,很牛,然后在那家公司我拼命跟着他学,讲真的,学到了好多好多东西,进这家公司的时候,人家给我定级是初中级自动化,在这做了一年多后再跳槽,我发现面试的题目我基本一看就会,跳到下一家直接就是高级了,所以,如果能跟这种大牛一起共事,一定要多学,现在我到新公司做接口自动化,然后在开发一个测试平台(突然发现,自己还是涉足挺广),我相信,当我找下一份工作的时候,要么就是测试经理,要么就是高级测试开发了,
总结:行业到底还能不能行 所以不要说测试这个行业没前途,这种话都是那些不上进的,自暴自弃的人说的;还有就是,做测试的最终归属不一定非得是自动化或者测开,做功能测试一样可以很牛,我一个朋友在一家金融公司只做功能,人家年年拿优秀员工,年终奖比那些做自动化,性能的都多;不要考虑太多,扎实做好当下的每一件事,有时间就去学习充实自己,扩展自己知识的广度,加深自己专业领域的深度,这样的人永远都不会被淘汰
自动化测试相关教程推荐: 2023最新自动化测试自学教程新手小白26天入门最详细教程,目前已有300多人通过学习这套教程入职大厂!!_哔哩哔哩_bilibili 2023最新合集Python自动化测试开发框架【全栈/实战/教程】合集精华,学完年薪40W+_哔哩哔哩_bilibili 测试开发相关教程推荐 2023全网最牛,字节测试开发大佬现场教学,从零开始教你成为年薪百万的测试开发工程师_哔哩哔哩_bilibili postman/jmeter/fiddler测试工具类教程推荐 讲的最详细JMeter接口测试/接口自动化测试项目实战合集教程,学jmeter接口测试一套教程就够了!!_哔哩哔哩_bilibili 2023自学fiddler抓包,请一定要看完【如何1天学会fiddler抓包】的全网最详细视频教程!!_哔哩哔哩_bilibili 2023全网封神,B站讲的最详细的Postman接口测试实战教学,小白都能学会_哔哩哔哩_bilibili 总结: 光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。 如果对你有帮助的话,点个赞收个藏,给作者一个鼓励。也方便你下次能够快速查找。
如有不懂还要咨询下方小卡片,博主也希望和志同道合的测试人员一起学习进步
在适当的年龄,选择适当的岗位,尽量去发挥好自己的优势。
我的自动化测试开发之路,一路走来都离不每个阶段的计划,因为自己喜欢规划和总结,
测试开发视频教程、学习笔记领取传送门!!
235. 二叉搜索树的最近公共祖先 思想:和二叉树的公共最近祖先节点的思路基本一致的!就是不用从下往上遍历处理!可以利用的二叉搜索树的特点从上往下处理了!而且最近公共节点肯定是第一个出现在【q,p】这个区间的内的! # Definition for a binary tree node. # class TreeNode: # def __init__(self, x): # self.val = x # self.left = None # self.right = None class Solution: def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': return self.lowestCommonAncestor1(root, p, q) def lowestCommonAncestor1(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': # 二叉搜索树,是有序的,不同于二叉树的公共祖先需要从下往上遍历 # 而且公共节点一定会出现在【p,q】之前,我们递归遍历,最先出现在这个区间就是公共祖先节点了 if root is None: return root # 处理中节点了 if root.val > q.
12月20日消息,今日, 腾讯宣布,QQ9正式上线。距离上一次QQ8版本已经过去了4年。 据官方介绍,本次版本更新,QQ9采用了全新的QQNT技术架构驱动,性能升级,交互体验更加流畅。全新界面,流畅社交。
首先是UI界面全面优化,QQ启动页、登录页、消息列表页、关于页等页面UI焕彩上线。
同时,聊天、设置界面顶部栏调整为浅色显示,聊天界面排版、图标进行了整体优化,视觉上更加简单纯粹。
其次,个人资料卡可以动起来了。迷你窝上线资料卡封面,可以为自己打造专属3D立体迷你窝,迷你窝还能随手机水平状态旋转。
第三,邀请好友绑定密友关系,即可获得对应好友标识,开启专属密友卡片。情侣关系支持且仅支持绑定一位好友,你是不是对象的唯一?绑定情侣关系一秒识别!
第四,QQ群全面升级,在线群文件预览上线。QQ9新增多群管理,群互动概况一目了然。群文件支持在线预览,减轻内存压力。
新增群成员去重、满员换群功能,避免成员重复进群,群管理更加便捷。
目前,腾讯QQ9安卓、iOS、Windwos、Linux、Mac版本已均可下载。
以下为QQ9更新一览:
目录
162. 寻找峰值
题目描述:
实现代码与解析:
二分
原理思路:
1901. 寻找峰值 II
题目描述:
实现代码与解析:
二分
原理思路:
162. 寻找峰值 题目描述: 峰值元素是指其值严格大于左右相邻值的元素。
给你一个整数数组 nums,找到峰值元素并返回其索引。数组可能包含多个峰值,在这种情况下,返回 任何一个峰值 所在位置即可。
你可以假设 nums[-1] = nums[n] = -∞ 。
你必须实现时间复杂度为 O(log n) 的算法来解决此问题。
示例 1:
输入:nums = [1,2,3,1] 输出:2 解释:3 是峰值元素,你的函数应该返回其索引 2。 示例 2:
输入:nums = [ 1,2,1,3,5,6,4] 输出:1 或 5 解释:你的函数可以返回索引 1,其峰值元素为 2; 或者返回索引 5, 其峰值元素为 6。 提示:
1 <= nums.length <= 1000-231 <= nums[i] <= 231 - 1对于所有有效的 i 都有 nums[i] !
软件:Portal V17 MATLAB R2021b
硬件:西门子s7-1200(DC/DC/DC)
1、博途中新建一个空白项目,CPU为1212DC/DC/DC(与自己手上的设备对应),在默认变量表中新建四个变量,其中TCON_Req控制TCON模块用于建立通信连接,TDIS_Req控制TDISCON模块用于断开通信连接,TSEND_Req控制TSEND模块用于控制PLC向Matlab发送数据,TRCV_Req控制TRCV模块用于控制PLC接收Matlab的数据。
2、主程序中添加TCON块(指令--通信--开放式用户通信--其他)并进行组态
3、连接参数中,伙伴选择“未指定”,新建连接数据,连接类型选择TCP,连接ID1,伙伴地址填写matlab所在主机ip地址,端口2000
4、主程序中添加TDISCON、TSEND、TRCV三个模块
5、程序块中添加全局DB块,新增两个Byte变量,PLC_to_Matlab和Matlab_to_PLC,分别用于TSEND和TRCV块的data端,然后编译代码,下载至PLC中运行代码启用监视
6、Matlab中新建脚本,输入t=tcpip('192.168.0.1', 2000, 'NetworkRole', 'Server');前两个参数为PLC的IP地址和本机端口号,保持代码并运行,命令行窗口打开执行fopen(t)打开TCP连接,然后去博途内修改TCON_Req为1然后修改为0(REQ端上升沿有效),matlab和plc建立通讯成功
7、TSEND的数据块写入33,通过matlab接收(TSEND的REQ端置1后置0)
8、matlab向PLC写入33,PLC接收(TRCV的REQ端置1后置0)
微服务架构中,常见的配置中心包括以下几种:
Spring Cloud Config:
Spring Cloud Config是官方推荐的配置中心解决方案,它支持将配置文件存储在Git、SVN等版本控制系统中。通过提供RESTful API,各个微服务可以远程获取和更新配置信息。这种方式使得配置变更能够快速、方便地在所有服务中生效。ZooKeeper: ZooKeeper是一个开源的分布式协调服务,它可以作为配置中心使用。服务可以通过ZooKeeper的节点数据来存储和获取配置信息。当配置发生变化时,ZooKeeper可以通知订阅的客户端进行更新。Nacos:
Nacos是阿里巴巴开源的一款集成了配置管理、服务发现、动态DNS服务于一体的平台。作为配置中心,Nacos支持集中化管理配置,提供动态配置推送功能,使得微服务能够实时获取最新的配置信息。Apollo:
Apollo是携程开源的分布式配置中心,它提供了统一的配置管理界面,支持多环境、多数据中心配置管理,以及配置修改的灰度发布等功能。etcd:
etcd是CoreOS开发的一个分布式键值存储系统,它可以用于存储和服务发现,包括作为微服务的配置中心。etcd提供了一致性保证和-watch机制,使得服务能够实时感知配置变化。Consul:
Consul是HashiCorp公司推出的工具,它包含了服务发现、健康检查、KV存储等功能,也可以用作配置中心。Consul的KV存储可以用来存储和获取配置信息,并通过其API或DNS接口实现配置的动态获取。 这些配置中心的主要目标是实现配置的集中管理和动态更新,以降低系统的复杂性和提高运维效率。选择哪种配置中心通常取决于项目的具体需求、技术栈和团队的经验。
【linux系统】 1.sudo yum install nfs-utils 或 sudo apt install nfs-common
问题:如果apt install nfs-common报错dpkg: error processing package rpcbind (--configure) 解决方法:删除所有信息之后update
sudo mv/var/lib/dpkg/info/ /var/lib/dpkg/info_old/
sudo mkdir/var/lib/dpkg/info/
sudo apt-get update
再apt install nfs-common成功
2.在客户端/home/uxdb/建挂载目录nfs
3.挂载命令 sudo unmount -t nfs -o nfsvers=3 192.30.0.134:/g/nfs /home/uxdb/nfs 解挂载 sudo umount /home/uxdb/nfs
4.检查挂载情况:showmount -e 192.30.0.134
【windows系统】 1.搭建NFS服务器
安装nfs.exe,配置输出表exports文件
链接:https://pan.baidu.com/s/16zXYDI0-YA5zZxvIa1djig 提取码:1kgm
NFS页不用配置,点击服务器页,点击编辑输出表文件
g:\nfs 是共享的文件夹路径,共享G盘下得nfs目录
-public表示公共权限
-name:nfs表示显示为什么名字。
编辑完成点击重启服务器
选择电脑,鼠标右键,点击管理,进入服务,找到NFS Server,鼠标右键,点击重新启动
就会看到输出界面显示exports配置的信息。
2.客户端挂载共享目录
mount 192.168.53.189:/g/nfs g/nfs
Linux是一个多用户、多任务的操作系统,它允许系统管理员通过用户组管理用户权限。用户组是一种方便的方式,可以将一系列权限分配给多个用户。本文将指导您如何在Linux系统中向组添加用户以及如何从组中删除用户。
添加用户到组 在Linux中,您可以使用usermod命令将现有用户添加到组。以下是如何操作的步骤:
使用usermod命令和-aG选项将用户添加到组。这里的-a表示追加,-G指定组名。例如,要将用户john添加到sudo组,可以使用以下命令: sudo usermod -aG sudo john 确认用户已成功添加到组中,可以使用id命令查看用户的组成员资格: id john 请注意,这将立即生效,但是用户john需要注销并重新登录才能应用新的组设置。
从组中删除用户 如果您需要从组中删除用户,可以使用gpasswd或deluser(Debian及其衍生系统)命令。这里是如何操作的步骤:
使用gpasswd命令和-d选项从组中删除用户。例如,要将用户john从sudo组中删除,可以使用以下命令: sudo gpasswd -d john sudo 在Debian或Ubuntu系统中,您可以使用deluser命令: sudo deluser john sudo 同样,您可以使用id命令确认用户已从组中删除: id john 用户john将不再显示在sudo组中。
重要提示 在添加或删除用户组成员时,请确保您有适当的权限。通常,您需要具有root权限或sudo权限。操作用户组时要格外小心,因为错误的操作可能会影响系统安全和用户权限。用户在下一次登录时,组的变更才会完全生效。 结论 通过用户组管理,Linux提供了一种灵活而强大的方式来控制用户对系统资源的访问。添加或删除组成员是日常系统管理任务的一部分,了解如何正确执行这些操作对于任何系统管理员来说都是重要的。希望这篇文章能帮助您更好地理解和管理Linux系统中的用户组。
窗口:将无限数据切割成有限的“数据块”进行处理,以便更高效地处理无界流
在处理无界数据流时,把无界流进行切分,每一段数据分别进行聚合,结果只输出一次。这就相当于将无界流的聚合转化为了有界数据集的聚合
Flink “存储桶” 在 Flink 中,窗口可以把流切割成有限大小的多个“存储桶”(bucket);每个数据都会分发到对应的桶中,当到达窗口结束时间时,就对每个桶中收集的数据进行计算处理
窗口处理过程:
窗口创建:
Flink 中窗口并不是静态准备好的,而是动态创建——当有落在这个窗口区间范围的数据达到时,才创建对应的窗口
窗口分类 按照驱动类型分类 驱动类型,即窗口以什么标准来开始和结束数据的截取
按照时间段截取:时间窗口
窗口大小:用结束时间减去开始时间,得到这段时间的长度,就是窗口的大小
Flink中用TimeWindow类来表示时间窗口:
可以看到,窗口的时间范围是左闭右开的区间
按照固定的个数截取:计数窗口
计数窗口基于元素的个数来截取数据,到达固定的个数时就触发计算并关闭窗口
按照窗口分配数据的规则分类 滚动窗口 滚动窗口有固定的大小,是一种对数据进行“均匀切片”的划分方式;
窗口之间没有重叠,也不会有间隔,是“首尾相接”的状态,所以每个数据都会被分配到一个窗口,而且只会属于一个窗口
滚动窗口可以基于时间定义,也可以基于数据个数定义;需要的参数只有一个,就是窗口的大小(window size)。比如我们可以定义一个长度为 1 小时的滚动时间窗口,那么每个小时就会进行一次统计;或者定义一个长度为 10 的滚动计数窗口,就会每 10 个数进行一次统计
滑动窗口 滑动窗口的大小也是固定的,但窗口之间并不是首尾相接的,而是可以“错开”一定的位置
参数:窗口大小和滑动步长
窗口大小是固定的,代表了两个窗口结束时间的间隔
滑动步长代表了窗口计算的频率。滑动的距离代表了下个窗口开始的时间间隔
当滑动步长小于窗口大小时,滑动窗口就会出现重叠,这时数据也可能会被同时分配到多个窗口中;具体的个数,就由窗口大小和滑动步长的比值来决定;
比如我们定义的窗口长度为 1 小时、滑动步长为 30 分钟,那么对于 8 点 55 分的数据,应该同时属于[8 点, 9 点)和[8 点半, 9 点半)两个窗口;而对于 8 点 10 分的数据,则同时属于[8点, 9 点)和[7 点半, 8 点半)两个窗口
会话窗口 数据来了之后就开启一个会话窗口,如果接下来还有数据陆续到来,那么就一直保持会话;如果一段时间一直没收到数据,那就认为会话超时失效,窗口自动关闭会话窗口只能基于时间来定义;因为“会话”终止的标志就是“隔一段时间没有数据来”参数:会话的超时时间会出现的问题:相邻两个数据的时间间隔 gap大于指定的 size,我们认为它们属于两个会话窗口,前一个窗口就关闭;可在数据乱序的情况下,可能会有迟到数据,它的时间戳刚好是在之前的两个数据之间的。这样一来,之前我们判断的间隔中就不是“一直没有数据”,而缩小后的间隔有可能会比 size 还要小——这代表三个数据本来应该属于同一个会话窗口解决方法:每来一个新的数据,都会创建一个新的会话窗口;然后判断已有窗口之间的距离,如果小于给定的 size,就对它们进行合并(merge)操作 全局窗口 全局有效,会把相同 key 的所有数据都分配到同一个窗口中(就相当于没有分窗口)默认是不会做触发计算的。如果希望它能对数据进行计算处理,还需要自定义“触发器”(Trigger) Flink 中的计数窗口(Count Window),底层就是用全局窗口实现的
题目描述:
部门在进行需求开发时需要进行人力安排。当前部门需要完成N个需求,需求用requirements[]表示,requirements[i]表示第i个需求的工作量大小,单位:人月。
这部分需求需要在M个月内完成开发,进行人力安排后每个月的人力是固定的。
目前要求每个月最多有2个需求开发,并且每个月需要完成的需求不能超过部门人力。请帮部门评估在满足需求开发进度的情况下,每个月需要的最小人力是多少?
输入描述:输入第一行为M和requirements,M表示需要开发时间要求,requirements表示每个需求工作量大小,N为requirements长度
1 <= N/2 <= M <= N <= 10^4
1 <= requirements[i] <= 10^9
输出描述:对于每组测试数据,输出部门需要人力需求,行末无多余空格
补充说明:
示例 示例1
输入:3
3 5 3 4
输出:6
说明:输入数据两行,第一行输入数据3表示开发时间要求,第二行输入数据表示需求工作量大小,输出数据一行,表示部门人力需求
作用 @Observed、@ObjectLink装饰器用于在涉及嵌套对象或者数组元素为对象的场景中进行双向数据同步。
状态的使用 1.嵌套对象 我们将父类设置为@Observed状态,这个时候,子应该设置@ObjectLink才能完成数据的双向绑定,所以我们构建一个组件,让状态变成一个变量来完成属性的状态化。
@Observed class Person{ name: string age: number gf: Person constructor(name:string, age: number, gf?: Person) { this.name = name this.age = age this.gf = gf } } @Entry @Component struct Parent { @State p: Person = new Person('zhangsan',21,new Person('lisi',18)) build() { Row() { Column() { Child({p:this.p.gf}) .onClick(()=>this.p.gf.age++) } .width('100%') } .height('100%') } } @Component struct Child{ @ObjectLink p: Person build(){ Column(){ Text(`${this.p.name} : ${this.p.age}`) } } } 2.
博客有3万访问量了呢。自从第一次用了赠送的1500的流量券,粉丝了从零突破了,到现在有150个粉丝了。
之前预想的写博客的初衷,也是记录自己的学习过程,毕竟好记忆不如烂笔头,记录下来就是长长久久的,随时可以翻阅。每个人都应该建立自己的知识库,包含自己各个方面的知识积累,每一个阶段都有每个阶段的兴趣爱好,任务目标,所以建立相应的知识库,可以帮助自己在对应的阶段,更好的成长,走的更顺利些。
我写博客也是记录自己学习python的过程。结识编程好多年了,至少20年了吧。刚开始就想学java,后来想学c#,都没学会,教程倒是买了不少,以前在北风网就买了不少教程。 学习各种语言,最后就精通了hello world。现在40+岁了,AI也特别的火,互联网那么多风口,都没把我吹起来,意志力不够还是能力有限?现在就想把python学会,至少等到退休后,能把自媒体做起来,有一份退休收入吧。
最近在学python窗体设计。就有一个想法,本地就用exe窗体,web端就建立一个展示的页面,也不需要后台,那不是简单也安全多了?本地负责收集处理伪原创,建立内容,写入数据库里,web端就从数据库里直接读取,组成页面,这样自主性就大多了。这样一个文章系统就只有页面展示,没有后台,安全性应该很高吧?就凭安全性,感觉这里面就有不少市场啊。
python窗体有难度,但用了pythonstudio后,就容易多了。先把pythonstudio的文档完成,根据作者的ppt内容,直接复刻,就是ppt里面很多都是图片,不过这也容易,通过软件转换一下,就可以复制了。
要学的内容还有好多,ai发展也非常非常迅猛,真害怕就这么错过了。学以致用,用以致赚。赚到了,有用了,得利了,才是真的学好了。
原创扣字不易,还请尊重原创,转载需注明源出处!!! 我们在实际的使用过程中,SPI也是较为常用的通讯方式,像flahs芯片,一些传感器,通讯模组 等会使用到这种通讯方式。
芯旺微的SPI外设简介
SPI 模块可配置为支持 SPI 协议或者 I2S 协议。SPI 模块默认工作在 SPI 方式,可通过软件将其切换到 I2S 模式。在 I2S 模式下,原则上数据传输为全双工模式,主机和从机同时收发数据,但实际情况下通常只有一个方向上的数据是有意义的。
本次主要讲解SPI主机和SPI从机配置以及收发方式。文章较长,可根据自己的需要进行选择。
SPI主机配置 注意:这里主机放在循环里面进行收发演示的,同步通讯,无需担心被打断等。
三步走:配置GPIO引脚 , 配置外设设置 , 配置外设中断
这里如何查询引脚可以重映射为什么功能就不细说了,可以翻阅其他文章有说。
1、配置GPIO引脚 ,这里做为主机将 时钟脚 , MOSI , MISO 配置为重映射引脚,将片选脚配置为GPIO输出脚。
void Spi_IO_Init() { /* Configure SPI0 IO */ GPIO_Write_Mode_Bits(GPIOD_SFR, GPIO_PIN_MASK_3, GPIO_MODE_RMP); //sck GPIO_Write_Mode_Bits( GPIOD_SFR, GPIO_PIN_MASK_2, GPIO_MODE_RMP); //sdi GPIO_Write_Mode_Bits(GPIOG_SFR, GPIO_PIN_MASK_15, GPIO_MODE_RMP); //sdo GPIO_Write_Mode_Bits( GPIOG_SFR, GPIO_PIN_MASK_14, GPIO_MODE_OUT); //cs GPIO_Pin_RMP_Config(GPIOD_SFR, GPIO_Pin_Num_3, GPIO_RMP_AF4); GPIO_Pin_RMP_Config(GPIOD_SFR, GPIO_Pin_Num_2, GPIO_RMP_AF4); GPIO_Pin_RMP_Config(GPIOG_SFR, GPIO_Pin_Num_15, GPIO_RMP_AF4); // GPIO_Pin_RMP_Config(PG14_SPI2_SS0_AF4); } #define SPI_CS_ENABLE GPIO_Set_Output_Data_Bits(GPIOG_SFR, GPIO_PIN_MASK_14, Bit_RESET) #define SPI_CS_DISABLE GPIO_Set_Output_Data_Bits(GPIOG_SFR, GPIO_PIN_MASK_14, Bit_SET) 2、配置外设设置:主要的点是:时钟源选择(涉及到波特率),spi模式(这里选择的是空闲时为低,第一个时钟沿发送数据),数据位数(这里选择8位),发送接收接口函数配置。以下为配置及注释
要实现一个数字人软件设计,可以使用 Python 结合一些库和框架来实现。以下是一个简单的示例代码,用于生成一个数字人的外观设计:
import random import matplotlib.pyplot as plt from PIL import Image, ImageDraw # 创建一个空白画布 canvas_width = 400 canvas_height = 400 canvas = Image.new('RGB', (canvas_width, canvas_height), 'white') draw = ImageDraw.Draw(canvas) # 设置数字人的特征参数 head_radius = random.randint(50, 100) body_height = random.randint(150, 250) arm_length = random.randint(70, 120) leg_length = random.randint(90, 150) eye_color = random.choice(['blue', 'green', 'brown']) hair_color = random.choice(['black', 'brown', 'blonde']) # 绘制头部 head_center = (canvas_width // 2, head_radius) head_bbox = (head_center[0] - head_radius, head_center[1] - head_radius, head_center[0] + head_radius, head_center[1] + head_radius) draw.
文章目录 一、爬取目标二、实现效果三、准备工作四、获取免费代理IP4.1 使用代理的好处?4.2 获取免费代理4.3 获取代理 五、代理实战5.1 导入模块5.2 设置翻页5.3 获取图片链接5.4 下载图片5.5 调用主函数5.6 完整源码 六、总结书籍推荐 一、爬取目标 本次爬取的目标是 又又又一个 某网站4K高清小姐姐图片:
二、实现效果 实现批量下载指定关键词的图片,存放到指定文件夹中:
三、准备工作 Python:3.10
编辑器:PyCharm
第三方模块,自行安装:
pip install requests # 网页数据爬取 pip install lxml # 提取网页数据 四、获取免费代理IP 4.1 使用代理的好处? 爬虫使用代理IP的好处有以下几点:
轮换IP地址:使用代理IP可以轮换IP地址,降低被封禁的风险,从而保持爬取的连续性和稳定性。提高采集速度:代理IP可以提供多个IP地址,使得爬虫能够同时进行多个线程使用,从而加快数据的采集速度。绕过反爬虫机制:许多网站采取了各种反爬虫机制,例如IP封禁、验证码、请求频率限制等。使用代理IP可以帮助爬虫绕过这些机制,保持正常的数据采集。保护个人隐私:使用代理IP可以帮助隐藏真实的IP地址,保护个人身份和隐私信息。 博主最近发现一款还不错的代理IP,易品HTTP家的高匿名代理IP,注册就可以免费领取1G的流量非常香:点击免费试用
4.2 获取免费代理 1、打开易品HTTP官网:点击免费试用
2、所有代理IP都需要实名认证一下才可以使用,不会的参考实名教程:实名教程
2、选择白名单 》添加白名单:
3、点击API提取 》 选择直连提取:
4、选择流量提取,点击生成API链接(我们这里有1G免费流量随便使用):
如果还是不会提取免费代理IP的可以询问 左下角的客服:
4.3 获取代理 获取到图片链接后我们需要再次发送请求去下载图片,由于请求量一般会很大所以需要用到代理IP。上面我们已经手动获取到了代理IP,下面来看Python如何挂上代理IP发送请求:
1、通过爬虫去获取API接口的里面的代理IP(注意:下面代理URL,看4.2教程换成自己的API链接):
import requests import time import random def get_ip(): url = "这里放你自己的API链接" while 1: try: r = requests.
文本分类定义 - text classification 文本分类是一种机器学习,它将文本文档或句子分类为预定义的类或类别。 它分析文本的内容和含义,然后使用文本标签为其分配最合适的标签。
文本分类的实际应用包括情绪分析(确定评论中的正面或负面情绪)、垃圾邮件检测(如发现垃圾电子邮件)和主题分类(如将新闻文章组织到相关主题中)。 文本分类使计算机能够理解和组织大量非结构化文本,在自然语言处理 (NLP) 中发挥着重要作用。 这简化了内容过滤、推荐系统和客户反馈分析等任务。
文本分类的类型 你可能遇到的文本分类类型包括:
文本情感分析确定 (text sentiment analysis) 一段文本中表达的情感或情感,通常将其分类为积极、消极或中性。 它用于分析产品评论、社交媒体帖子和客户反馈。与文本情感分析相关的毒性检测 (toxicity detection) 可识别在线攻击性或有害语言。 它帮助在线社区的版主在在线讨论、评论或社交媒体帖子中维护一个相互尊重的数字环境。意图识别 (intent recoginition) 是文本情感分析的另一个子集,用于理解用户文本输入背后的目的(或意图)。 聊天机器人和虚拟助理通常使用意图识别来响应用户查询。二元分类 (biary classification) 将文本分为两个类或类别之一。 一个常见的例子是垃圾邮件检测,它将文本(例如电子邮件或消息)分类为垃圾邮件或合法类别,以自动过滤掉未经请求的和可能有害的内容。多类分类 (multiclass classification) 将文本分为三个或更多不同的类或类别。 这使得从新闻文章、博客文章或研究论文等内容中组织和检索信息变得更加容易。主题分类 (topic categorization) 与多类分类相关,将文档或文章分组为预定义的主题或主题。 例如,新闻文章可以分为政治、体育和娱乐等主题。语言识别 (language identification) 确定一段文本的书写语言。 这在多语言环境和基于语言的应用程序中非常有用。命名实体识别 (named entity recognition) 侧重于对文本中的命名实体进行识别和分类,例如人名、组织、位置和日期。问题分类涉 (question classifcation) 及根据预期答案类型对问题进行分类,这对于搜索引擎和问答系统非常有用。 文本分类过程 文本分类过程涉及从数据收集到模型部署的几个步骤。 以下是其工作原理的快速概述:
第 1 步:数据收集 收集一组文本文档及其相应的类别,用于文本标记过程。
步骤2:数据预处理 通过删除不必要的符号、转换为小写字母以及处理标点符号等特殊字符来清理和准备文本数据。
第 3 步:分词 将文本分解为标记,这些标记是像单词一样的小单元。 标记通过创建单独的可搜索部分来帮助查找匹配和连接。 此步骤对于向量搜索和语义搜索特别有用,它们根据用户意图给出结果。
第四步:特征提取 将文本转换为机器学习模型可以理解的数字表示。 一些常见的方法包括计算单词的出现次数(也称为词袋)或使用单词嵌入来捕获单词含义。
第五步:模型训练 现在数据已清理并经过预处理,你可以使用它来训练机器学习模型。 该模型将学习文本特征及其类别之间的模式和关联。 这有助于它使用预先标记的示例来理解文本标记约定。
文章目录 1. 实现目标2. 开发应用3. 编写 Dockerfile4. 构建镜像5. 测试应用6. 场景运用7. 镜像入库 1. 实现目标 实现一个go 开发 demo web,并实现构建镜像,运行容器,推送镜像入库。 2. 开发应用 开发环境:linux 、windows、mac
package main import ( "fmt" "html" "log" "net/http" ) func main() { fmt.Println("launching server at port 9090") http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "hello, %q", html.EscapeString(r.URL.Path)) }) log.Fatal(http.ListenAndServe(":9090", nil)) } 第一个终端执行:
$ go run main.go launching server at port 9090 第二个终端模拟客户端访问,效果如下:
$ curl http://localhost:9090/docker-go hello, "/docker-go" $ curl http://localhost:9090/google hello, "
表结构创建、表结构备份 只创建表结构,没有数据
create table 新表名 as select * from 旧表名 where 1=2 表数据备份 创建表结构并且备份表数据
create table 新表名 as select * from 旧表名
1.先准备一个ico图标文件,可以自己做一个,或者到一些网站找找,比如下面这个
4,554 locker icons - Iconfinder
2.然后转换完毕将xxx.ico图标文件放到与.pro同一个目录下
3.在.pro文件添加一行代码
RC_ICONS = xxx.ico //xxx.ico为所需要设置的图标,可以替换成自己需要的 编译运行,可执行exe应用程序图标就变成你想要的效果了
目的:修改对象node的child属性的值,页面响应式变化
问题:数据是变了,但是页面没反应;在页面中用v-if绑定这个值,数据变了,视图也是不更新
错误写法: this.node.child = "" 正确写法: this.$set(this.node, "child", ""); 双向绑定的修改数据机制 我们使用v-if是一个双向绑定的过程 v-if:"isCommentShow[i]"
vue对于双向绑定的监视,是通过特定的方式实现的。如果双向绑定的对象是基本类型,则不影响。而如果双向绑定的变量是一个对象,是一个具有多个属性的对象,则需要响应式的绑定。
vue实现对对象的双向数据绑定的原理就是利用了 Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。如果要给对象添加新的属性,此时新属性没有进行过上述过程,是不会响应的。
我们如果直接修改变量的值,即this.变量 = 新值这种方式是没有经历重写的set方法的。双向绑定是没办法监听到我们的修改的。所以当我们修改了,输出的也是新值。但是你要让双向绑定知道你修改了才行,不是你改了,双向绑定就立刻知道你改了。
也就是我们需要用vue的规则去改,去通过对象重写的set方法去改对象的属性来达到响应式修改,能够立刻通知到双向绑定的指令,我修改了。
这个规则就是:this.$set(this.对象,属性名,新值)。
总结 v-if不要绑定数组元素,无效,数组元素内容的变化无法响应v-if
v-if绑定对象属性 {1: true, 2: false},如果提前写死,v-if绑定其中一个属性,则可以生效v-if
如果对象的属性数量不定,是通过某方法的触发去改变对象的属性数量。需要使用$set()去更改对象的值, 如:
//增改都适用 this.$set(this.对象名, 属性名, 新值) //不可以使用下面的方法更新 this.对象.属性 = 新值 //或者 this.对象[属性] = 值 只要所有修改或者增加属性的语句都使用this.$set() ,就能解决 v-if 无法响应对象中动态变化的属性的问题。
————————————————
原文链接:https://blog.csdn.net/NineWaited/article/details/126258442
未整理
使用了this.$set,数据更新了,页面依旧不更新(vue2 就是说今天出现了另一个问题,使用了this.$set(),控制台打印出来数据更新了,但是页面视图没有更新 问题重现: export default { data() { return { node: { a: "" }, } }, method:{ // 这里是先执行了其他操作,在里面给node增加了一个属性b 并赋值了 this.
用于向NTP服务器请求时间。向NTP服务器发送一个48字节大小的请求报文,再使用recvfrom()函数接收服务器的响应。最后,解析得到的时间戳并转换为Unix时间进行显示。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <unistd.h> #include <time.h> #define NTP_SERVER_IP "ntp1.aliyun.com" #define NTP_SERVER_PORT 123 #define NTP_PACKET_SIZE 48 // NTP报文结构体 struct ntp_packet { uint8_t flags;// 标志位,使用0x1B表示客户端请求时间信息 uint8_t stratum;// stratum层级,一般使用1表示客户端直接与服务器通信 uint8_t poll;// 投票计数器,表示网络状况,一般使用0或10表示正常情况 uint8_t precision;// 时间精度,一般使用0或10表示正常情况 uint32_t rootDelay;// 服务器到客户端的延迟,单位是秒 uint32_t rootDispersion;// 服务器到客户端的散度,单位是秒 uint32_t referenceIdentifier;// 参考标识符,通常是服务器的IP地址或域名 uint32_t referenceTimestamp[2];// 参考时间戳,一般是服务器的本地时间 uint32_t originateTimestamp[2];// 起始时间戳,一般是客户端发送请求的时间 uint32_t receiveTimestamp[2];// 接收时间戳,一般是服务器收到请求的时间 uint32_t transmitTimestamp[2];// 传输时间戳,一般是服务器发送响应的时间 }; int main() { int sockfd; struct sockaddr_in servaddr; // 创建套接字 sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) { perror("
在现代 IT 基础设施的动态环境中,高效的数据收集和分析至关重要。 Elastic Agent 是 Elastic Stack 的关键组件,通过促进将数据无缝摄取到 Elasticsearch 中,在此过程中发挥着至关重要的作用。 然而,显着影响此过程整体有效性的关键性能指标之一是延迟,即数据从 Elastic Agent 传输到 Elasticsearch 所需的时间。 在本文中,我们将深入研究捕获 Elastic Agent 和 Elasticsearch 之间的延迟时间。
有关如何设置 Agent 并采集数据,请阅读文章:
Observability:使用 Elastic Agent 来摄入日志及指标 - Elastic Stack 8.0
Observability:如何使用 Elastic Agents 把定制的日志摄入到 Elasticsearch 中
捕获延迟时间指南 利用处理器 (processors) 为所有事件合并代理 (agent) 时间戳。 处理器的目的是最小化导出事件中的字段或使用附加元数据对其进行扩充。 此操作发生在代理内,发生在日志进行解析之前。
让我们以系统 (System) 集成为例,以便更好地理解和计算延迟时间。
System Integration 展开收集指标 (Collect metrics) 部分并打开 System process metrics -> Advance Options。 添加脚本处理器,它将为所有事件添加代理时间戳。
在上面点击 “Advanced options”
Script Processor:
本文为官方文档直译版本。原文链接
使用 Spring Boot 开发 引言构建系统依赖管理 MavenGradleAntStarters结构化你的代码使用 "默认" 包查找主应用程序类配置类导入更多配置类导入 XML 配置 自动配置逐步取代自动配置禁用特定的自动配置类自动配置包 Spring Beans 和依赖注入使用 @SpringBootApplication 注解运行你的应用程序从集成开发环境中运行以包的形式运行使用 Maven 插件使用 Gradle 插件热部署 开发工具诊断类加载问题属性默认值自动重启记录条件评估中的变化排除资源监听更多路径禁用重启使用触发器文件自定义重启类加载器已知的局限性 LiveReload全局设置配置文件系统监视器 远程应用运行远程客户端程序远程更新 打包你的应用程序到生产 引言 本节将详细介绍如何使用 Spring Boot。它涵盖了构建系统、自动配置以及如何运行应用程序等主题。我们还将介绍一些 Spring Boot 最佳实践。尽管 Spring Boot 并没有什么特别之处(它只是另一个可以使用的库),但我们还是提出了一些建议,只要遵循这些建议,开发过程就会变得更加轻松。
如果您刚开始使用 Spring Boot,在阅读本节内容之前,最好先阅读入门指南。
构建系统 强烈建议您选择一个支持依赖关系管理的构建系统,该系统可以使用发布到 “Maven Central” 资源库的工件。我们建议您选择 Maven 或 Gradle。Spring Boot 也可以与其他构建系统(例如 Ant)配合使用,但它们的支持并不完善。
依赖管理 Spring Boot 的每个版本都会提供其支持的依赖项的精选列表。实际上,您无需在构建配置中提供这些依赖项的版本,因为 Spring Boot 会为您管理这些依赖项。当您升级 Spring Boot 本身时,这些依赖项也会以一致的方式升级。
如果需要,您仍然可以指定一个版本并覆盖 Spring Boot 的建议。
精选列表包含了可与 Spring Boot 配合使用的所有 Spring 模块,以及第三方库的细化列表。该列表以标准材料清单 (spring-boot-dependencies) 的形式提供,可与 Maven 和 Gradle 一起使用。
Elastic Stack 已成为监控任何环境或应用程序的实际解决方案。 从日志、指标和正常运行时间到性能监控甚至安全,Elastic Stack 已成为满足几乎所有监控需求的一体化解决方案。 Elasticsearch 通过提供强大的分析引擎来处理任何类型的数据,成为这方面的基石。
Elasticsearch 旨在处理 TB 级的数据。 然而,这并不意味着 Elasticsearch 或 ELK 可以开箱即用地完美处理任何工作负载。 在大多数情况下,这是由于缺乏性能调整来满足确切的监控需求。 性能调优是令许多 DevOps 和系统管理员专业人员感到沮丧的一方面。 为了在 Elasticsearch 方面缓解这个问题,我们来看看如何开始调整 Elasticsearch 集群的性能。
评估你的要求 我们当然可以将环境中的所有数据推送到 Elasticsearch,但更好的问题是这样做是否能带来任何切实的好处。 是的,将所有数据放在一个易于访问的平台中可以简化事情。 然而,推送所有数据意味着更大且快速增长的数据集。 这很快就会变得笨重、成本高昂,甚至导致性能调整几乎不可能的情况。
避免这种情况的最简单方法是了解你需要从监控平台完成什么任务,并确定需要捕获并推送到 Elasticsearch 的优先级。 对最重要的数据进行分类,并将优化重点放在集群上,以满足这些高优先级数据集的需求。 假设你通过 S3 捕获 AWS VPC 流日志,但没有主动监控它们,那么将这些数据推送到 Elasticsearch 只是为了在需要时能够分析它们,这会浪费资源。 更好的解决方案是将这些数据保存在 S3 中,并在需要时使用 AWS Athena 等工具查询数据,或者在需要高级分析功能时推送数据子集。 你节省的容量可以在其他地方更好地利用,例如 APM 或其他日志,例如将更定期使用的应用程序错误日志。
例如,如果部署的主要需求是监控指标,那么更快的摄取和处理是关键。 如果我们专注于推送日志,存储也会在优化中发挥重要作用。 这是一个平衡游戏,需要选择需要推送的内容并优化摄取管道、存储和处理。 由于业务优先级不断变化,用户必须定期评估以确定需要优化的领域并定期更新优化。
硬件 无论进行怎样的优化,如果底层硬件没有足够的资源来处理摄取、处理和存储时的数据负载,用户仍然会遇到性能问题。 由于 Elasticsearch 旨在处理更大的数据集,因此需要适当的硬件资源才能实现最佳功能。 硬件资源的主要考虑因素是CPU、RAM 和存储。 你不仅需要资源来处理数据,还需要运行所需的应用程序本身。 你可能已经为摄取节点分配了足够的资源,但如果你的 Kibana 实例没有必要的资源,则部署将无法使用。
首先确定数据的确切需求,并考虑以下因素