一、无论 某头文件 是否被 多个文件引用,都要加上#ifndef #endif。
试想:
有2个.c文件,都#include引用了 同一个.h文件;
编译时,两个.c文件 都要 一同编译 成一个 可运行文件;
那么会产生 声明冲突。
#idndef HAPPY_H //防止HAPPY_H被重复引用、重复编译 #define HAPPY_H ... #endif 举例:
某工程,有4个文件,dog.cpp dog.h aa.h bb.h
dog.cpp内容如下: #include aa.h #include bb.h aa.h和bb.h内容如下: #include dog.h dog.h内容如下 class Dog { .. } 我们发现:
dog.cpp头文件包含了aa.h bb.h
aa.h bb.h头文件又包含了dog.h
而dog.h又有class dog的定义
编译运行:
编译器 编译 dog.cpp时,先根据头文件,去编译 aa.h, 再根据aa里面的#include dog.h去编译dog.h文件,这样就把dog.h里面的class dog编译了;
然后再根据dog.cpp的第二句#include“bb.h”,去编译bb.h,再根据bb里面的#include dog.h去编译dog.h,但是之前class dog已经编译过了,所以会报 重定义 错误!
所以:
加上#ifndef #endif很重要,看来是每个文件都要加上。。
二、ifdef
描述:条件编译
#ifdef macro_definition
macro_definition为: 预处理器 定义的 宏,以将c源代码包含到已编译的应用程序中。
关于此问题,确实恶心了我一段时间,因为我笔记本的屏幕分辨率高,而分屏出来的显示器分辨率低,导致每次截图的时候总是以高分辨率来缩放,出现部分黑框,而且截图画面缩小到看不清楚,严重影响使用,为此头疼不已,废话不多说,直接上方法! 解决方法:鼠标右键桌面微信图标 -- 属性--兼容性--更改更高dpi设置--勾选 替代高dpi缩放行为 -- 确定 -- 应用 -- 重启微信 -- 问题解决
NiFi同步中文表、中文字段名 一 目的 假设Oracle数据库中有一个中文表,其字段名为纯中文。我们希望将表数据同步到MySQL数据库中,在MySQL数据库中创建同等类型的英文表名称和英文字段名称。那么在中文字段向英文字段同步过程中会出现异常导致不能直接同步。
二 表介绍 源表
CREATE TABLE ZXY.中文表_ZXY ( 姓名 VARCHAR(20) null, 性别 VARCHAR(20) null, 年龄 VARCHAR(20) null ) ; insert into "中文表_ZXY" values('小A','男','8'); insert into "中文表_ZXY" values('小B','女','9'); 目标表
create table zxy.c_zxy ( name varchar(20) null, sex varchar(20) null, age varchar(20) null ) ; 二 Nifi全量同步中文表-普通流程 最常见的全量同步,通过ExecuteSQL组件truncate目标表,使用ExecuteSQLRecord组件查询源表数据( AvroRecordSetWriter写数据),最后通过PutDataBaseRecord将数据存到目标表中( AvroReader读数据)。但是最后报错"due to None of the fields in the record map to the columns defined by the c_zxy table",中文表和英文表之间找不到映射关系,那么应该调整流程,使其具有映射关系。
三 Nifi全量同步中文表-自定义流程 整体流程使用七个组件,第一步通过ExecutSQL组件truncate目标表,第二步使用ExecuteSQLRecord组件查询源表数据( AvroRecordSetWriter写数据),第三步使用ConvertAvroToJSON组件将Avro数据转成JSON类型数据,第四步使用SplitJson将整个JSON切分成一条一条的JSON数据,第五步使用EvaluateJsonPath解析中文表的字段并将其映射为英文名,第六步使用ReplaceText获取上一步的参数并写成SQL语句insert into zxy.
Pycharm版本:2022.2.3
python版本:python3.9
目录
第一步:降低opencv版本
查看opencv版本
方法一:在cmd中输入
方法二:在pycharm中输入(或者其他python编辑器)
降低opencv版本
第二步:配置python
另外的方法:添加环境变量的方法
第一步:降低opencv版本 (不知道需不需要但是我做了这个操作)
其他文章说要退回4.6以后的Opencv版本,可以先查看自己的opencv版本
查看opencv版本 方法一:在cmd中输入 python
import cv2
cv2.__version__
方法二:在pycharm中输入(或者其他python编辑器) import cv2
print(cv2.__version__)
降低opencv版本 在pycharm的终端输入:
pip install --upgrade opencv-python<4.6
(我操作完发现还是不行)
第二步:配置python ok后显示:
然后神奇地发现,出现提示了
另外的方法:添加环境变量的方法 (因为成功了就没试了但应该可以)
最后一步选中你的cv2文件夹点0k就加入了
【单片机毕业设计项目分享系列】
🔥 这里是DD学长,单片机毕业设计及享100例系列的第一篇,目的是分享高质量的毕设作品给大家,包含全面内容:源码+原理图+PCB+实物演示+论文。
🔥 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的单片机项目缺少创新和亮点,往往达不到毕业答辩的要求,为此学长准备了相对容易且工作量达标,并包含创新点的项目分享给大家。
🧿 整理的题目标准:
相对容易工作量达标题目新颖,含创新点 🧿 项目分享:
https://gitee.com/sinonfin/sharing
课题项目1 : stm32单片机老人健康及跌倒检测系统 可检测温度(ds18b20模拟),心率,血氧和是否摔倒,GPS定位,屏幕显示,手机短信提示,蓝牙连接手机,可以自己设置单片机的联系手机号,检测数据异常,会给手机发送消息提示,单片机也会发出声响,提醒周围人
资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档
🥇项目综合综合评分(每项满分5分)
难度系数:3分工作量:4分创新点:4分 课题项目2:stm32智能平衡小车 (1) 直立控制功能:车模的倾角作为控制的输入量,使用PD算法,控制车模稳定在平衡位置。
(2) 速度控制功能:直立车模的速度控制与普通的车模速度控制不同,在直立系统中,速度控制是通过改变车模倾角来完成的。具体实施思路是,对电机转速加入干扰,使车身偏离平衡位置,以此刺激直立控制任务,从而达到控制速度的目的,速度控制使用PI算法。
(3) 方向控制功能:通过控制两个电机的差速来达到转向的目的,方向控制使用PD算法,使用X轴的角速度作为微分项的因子,可以极大改善转向的动态性能,避免振荡。
资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档
🥇项目综合综合评分(每项满分5分)
难度系数:3分工作量:4分创新点:4分 课题项目3:基于stm32与openmv的目标跟踪系统 1.通过OpenMV识别出被测物体(以红色小球为例)。
2.在OpenMV识别出目标物体后,判断物体所在区域,将区域信息通过串口传输给STM32。
3.利用STM32的串口部分的应用及原理知识,对接收到的数据进行处理。
4.利用STM32的应用及原理知识,对处理好的数据进行判断后,对舵机进行控制。
5.利用STM32的定时器部分和PWM控制的应用及原理知识,控制舵机,使其转动适当角度,使OpenMV对准目标物体。
资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档
🥇项目综合综合评分(每项满分5分)
难度系数:3分工作量:4分创新点:4分 课题项目4:基于STM32与wifi的天气预报网时钟系统 1)实时温度显示;
2)年月日星期时分秒显示;
3)年月日星期时分秒调整;
4)闹钟定时小时分钟和秒;
5)数据外部联网;
资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档
🥇项目综合综合评分(每项满分5分)
难度系数:3分工作量:4分创新点:4分 课题项目5:stm32的RFID与指纹识别的门禁系统 数据采集模块、 存储模块、 显示模块、 门控模块、 警报模块、 键盘模块和上位机软件的设计几个方面。
数据采集模块: 读卡器 YHY502ATG 通过天线读取 RFID 卡的数据,然后将数据传送出去。 存储模块: AT89C52 接收到数据后, 将数据传送给 AT24C04 进行存储。 显示模块: AT89C52 接收到数据后, 将数据与 AT24C04 里存储的数据进行对比, 若两者完全相同, 则液晶显示正确的信息; 若不相同, 则液晶显示错误的信息。 门控模块: AT89C52 接收到数据后, 将数据与 AT24C04 里存储的数据进行对比, 若两者完全相同, 则进行开门操作; 若不相同, 则不开门。 警报模块: AT89C52 接收到数据后, 将数据与 AT24C04 里存储的数据进行对比, 若不相同则报警。 键盘模块: 通过键盘输入密码, 并根据输入密码的有效性做相应的操作。 资料齐全,包含内容:源码+原理图+器件清单+实物焊接效果+详细文档
ASCII码转字符 char word=(char)97 //强制转换 字符转ASCII码 int value='a'; //加 ‘’
本课时我们主要介绍有哪些解决死锁的策略。
线上发生死锁应该怎么办 如果线上环境发生了死锁,那么其实不良后果就已经造成了,修复死锁的 最好时机在于“防患于未然”,而不是事后补救。就好比发生火灾时,一旦着了大火,想要不造成损失去扑灭几乎已经不可能了。死锁也是一样的,如果线上发生死锁问题,为了尽快减小损失,最好的办法是保存 JVM 信息、日志等“案发现场”的数据,然后 立刻重启服务,来尝试修复死锁。为什么说重启服务能解决这个问题呢?因为发生死锁往往要有很多前提条件的,并且当并发度足够高的时候才有可能会发生死锁,所以 重启后再次立刻发生死锁的几率并不是很大,当我们重启服务器之后,就可以暂时保证线上服务的可用,然后利用刚才保存过的案发现场的信息, 排查死锁、修改代码,最终重新发布。
常见修复策略 我们有哪些常见的对于死锁的修复策略呢?下面将会介绍三种主要的修复策略,分别是:
避免策略检测与恢复策略鸵鸟策略 它们侧重各不相同,我们首先从避免策略说起。
避免策略 如何避免
避免策略最主要的思路就是, 优化代码逻辑,从根本上消除发生死锁的可能性。通常而言,发生死锁的一个主要原因是顺序相反的去获取不同的锁。因此我们就演示如何通过 调整锁的获取顺序 来避免死锁。
转账时避免死锁
我们先来看一下转账时发生死锁的情况。这个例子是一个示意性的,是为了学习死锁所而写的例子,所以和真实的银行系统的设计有很大不同,不过没关系,因为我们主要看的是如何避免死锁,而不是转账的业务逻辑。
(1)发生了死锁
我们的转账系统为了保证线程安全, 在转账前需要首先获取到两把锁(两个锁对象),分别是被转出的账户和被转入的账户。如果不做这一层限制,那么在某一个线程修改余额的期间,可能会有其他线程同时修改该变量,可能导致线程安全问题。所以在没有获取到这两把锁之前,是不能对余额进行操作的;只有获取到这两把锁之后,才能进行接下来真正的转账操作。当然,如果要转出的余额大于账户的余额,也不能转账,因为不允许余额变成负数。
而这期间就隐藏着发生死锁的可能,我们来看下代码:
public class TransferMoney implements Runnable { int flag; static Account a = new Account(500); static Account b = new Account(500); static class Account { public Account(int balance) { this.balance = balance; } int balance; } @Override public void run() { if (flag == 1) { transferMoney(a, b, 200); } if (flag == 0) { transferMoney(b, a, 200); } } public static void transferMoney(Account from, Account to, int amount) { //先获取两把锁,然后开始转账 synchronized (to) { synchronized (from) { if (from.
目录
1、对外数据对接方案
2、代码实现
3、 总结
1、对外数据对接方案 一般者对外提供数据的方式通常有如下两种方案:
1、提供接口让接收数据方使用定时任务进行调用接口拉取数据【Pull方式】。
2、数据提供方使用定时任务Push数据到数据使用的第三方。【Push方式】
具体情况如下图所示: 2、代码实现 public void pushOverdueUserInfoToWaterSupply() throws Exception { //1、查询当前同步任务方法 上一次开始执行时间用于获得最新同步数据时间起点 DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); SysTimedTaskSyncDataLog sysTimedTaskSyncDataLog = sysTimedTaskSyncDataLogService. selectTimeTaskSyncDataLogSomeOneLatestOne(BusinessConstant.SYNC_OVERDUE_TYPE); String lastSynDateTime = LocalDateTime.now(ZoneOffset.of("+8")).format(format); LocalDateTime taskStartTime =sysTimedTaskSyncDataLog==null? LocalDateTime.now(ZoneOffset.of("+8")):sysTimedTaskSyncDataLog.getTaskStartTime(); System.out.println(taskStartTime.format(format)); List<OverdueUserInfoDto> overdueUserInfoList = selectSynOverdueUserInfoList(lastSynDateTime); //2、从本地业务数据库之中获得同步失败部分数据,同时同步成功后把中间表之中记录删除 processPushMistakeRecordOverdueUserInfoData(); //3、获得当前最后一次同步时间点到当前时间节点内的数据到供水一体化平台之中【数据来源saas】 progressPushOverdueUserInfoData(overdueUserInfoList); } 3、 总结 两种方式共享数据的时候在我们日常开发过程之中可能都会遇见,我本人是已经遇见了两种实现方式,Push方式在广东某项目之中实现过,目前正在实现的数据共享方式通过数据接收方Pull拉取接口。
注意事项:任何一种方式都得考虑实际情况之中一些容错状况,比如Pull方式最好限制每次拉取数据记录比如limitPageSize=1000,最长拉取数据时间未15天等等。必须传入开始时间startDate,和结束时间endDate等等。
/** * 验证共享数据参数 * @param reqVO * @param reqParam * @return */ private String validReqParamsBetweenDays(DataSharePageReqVO reqVO, DataSharePageMapperReqVO reqParam){ String startDate=reqVO.
目录
1、问题产生的背景
2、出现的现象
3、解决方案
4、成果展现
5、总结
6、参考文章
1、问题产生的背景 因为本人最近工作相关的对接外部项目,在我们国内有很多程序员都是使用汉语拼音或者部分字母加上英文复合体定义返回实体VO,这样为了能够符合对接方的字段要求。于是在定义返回实体类型需要按照对方要求进行定义。我是发现好些部分银行里面接口定义的字段也有类似情况。最近在对接一个供水平台的对外提供给某市的公共数据管理平台的时候就发现上述描述情况。 2、出现的现象 我在按照对应的文档要求定义了相关的返回实体VO,如下图所示。 结果在返回的请求响应结果如下图所示:
这样返回结果肯定不符合预期要求,那如何来解决这种问题呢?最后想到问题应该出在如下两个地方:
1、我使用Lombok,可能出现在此处
2、是否因为Bean的属性设置问题原因 经过网上查询相关资料,问题就出在Bean的定义属性。参数命名不规范原来的 POJO 的参数有【uCode】,这种命名而且 pojo 是 lombok 注解管理的 导致 jackson 自动转换成小写了。
3、解决方案 在 pojo 加上 @JsonAutoDetect (fieldVisibility= JsonAutoDetect.Visibility.ANY,getterVisibility= JsonAutoDetect.Visibility.NONE)
注解解释: @JsonAutoDetect 该注解用来 改变默认的自动检测,标记在类上
jackson默认大小写敏感,且首字母转小写 用来指定字段、方法的可见性规则 @JsonAutoDetect(fieldVisibility=JsonAutoDetect.Visibility.ANY,getterVisibility=JsonAutoDetect.Visibility.NONE) 4、成果展现 经过上面的注解的加入之后,达到了预期的效果。
5、总结 凡是遇见的问题,一般其他人应该也遇见过,需要自己思考搜索相关的关键字才能找到对应的解决方案,所以解决问题需要抓住问题的关键本质。如此问题需要搜索关键词 jackson 转 jsonjackson 转 json jackson 转 json参数大小写问题 返回字段大小写 不一致参数大小写问题
6、参考文章 https://my.oschina.net/u/4540973/blog/4657027
https://www.likecs.com/show-933963.html https://blog.csdn.net/weixin_45502734/article/details/124306296
摘要 很多的同学在开发的过程中对于JVM的生产环境不熟悉,导致缺乏JVM的优化和实战,本博文主要介绍JVm的优化指标和常用的JVM调优方式。同时结合JVM的常见问题给同学一个实战的案例,帮助同学理解和学习JVM的优化。
一、JVM调优的核心吞吐量、停顿时间、垃圾回收频率 调优之前首先我们要知道怎样才算是“优”,不能笼统的说我的程序性能很好,所以就需要有一个具体的指标来衡量性能情况,而在JVM里面衡量性能两个指标分别“吞吐量”和“停顿时间”。
1.1 吞吐量 程序运行过程中执行两种任务,分别是执行业务代码和进行垃圾回收,吞吐量大意就是说程序运行业务代码的时间越多程序的吞吐量就越高,其计算公式 ,吞吐量 = CPU在用户应用程序运行的时间 / (CPU在用户应用程序运行的时间 + CPU垃圾回收的时间),一般而言GC 的吞吐量不能低于 95%。
1.2 停顿时间 因为JVM进行垃圾回收的时候,某些阶段必须要停止业务线程专心进行垃圾收集,停顿时间就是指JVM停止业务线程而去进行垃圾收集的这段时长,停顿时间越长就意味着用户线程等待的时间越长,停顿时间会直接影响用户使用系统的体验。
1.3 垃圾回收频率 通常来说垃圾回收频率是越低越好,垃圾收集的过程是非常占用CPU资源的,资源有限如果垃圾收集占用的资源越多那么以为着其他事情所用的资源会减少,系统所能做的事情也会越少。当然也不能一味的追求GC次数减少,GC次数减少了有可能就会使得单次GC的时间变长,那么就可能会增加单次GC的“停顿时长”,所以需要在这两者之间做一些平衡。
在项目启动的时候 增加下列参数来收集收集GC日志,然后通过第三方的日志分析工具(GCesay:https://gceasy.io/)分析收集到的GC日志来得到吞吐量、停顿时间相关的统计数据。
java -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:+PrintHeapAtGC -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -Xloggc:/opt/ard-user-gc-%t.log -jar abg-user-1.0-SNAPSHOT.jar -Xloggc:/opt/app/ard-user/ard-user-gc-%t.log 设置日志目录和日志名称 -XX:+UseGCLogFileRotation 开启滚动生成日志 -XX:NumberOfGCLogFiles=5 滚动GC日志文件数,默认0,不滚动 -XX:GCLogFileSize=20M GC文件滚动大小,需开启UseGCLogFileRotation -XX:+PrintGCDetails 开启记录GC日志详细信息(包括GC类型、各个操作使用的时间),并且在程序运行结束打印出JVM的内存占用情况 -XX:+ PrintGCDateStamps 记录系统的GC时间 -XX:+PrintGCCause 产生GC的原因(默认开启) 1.4 调优的标准:吞吐量和停顿时间的选择 调优前首先要确定大方向,是选择基于吞吐量调优、还是停顿时间调优,哪个是你的硬性指标,这个硬性标准就是指导你进行调优的原则。如果你的应用和用户没有什么交互,完全不需要关注用户体验,那么你的硬性标准就是不顾一切的提升吞吐量,达到程序性能的最优。 相反如果你的应用是频繁和用户进行交互的,那么提升用户体验就是一个非常重要的指标了,这个时候你的原则就是在用户能忍受卡顿时间(停顿时间)范围之内,来调整指标来找到停顿时间和吞吐量的一个平衡值 。
二、JVM常用调优策略 2.1 选择合适的垃圾回收器 CPU单核,那么毫无疑问Serial 垃圾收集器是你唯一的选择。CPU多核,关注吞吐量 ,那么选择PS+PO组合。CPU多核,关注用户停顿时间,JDK版本1.6或者1.7,那么选择CMS。CPU多核,关注用户停顿时间,JDK1.8及以上,JVM可用内存6G以上,那么选择G1。 //设置Serial垃圾收集器(新生代) 开启:-XX:+UseSerialGC //设置PS+PO,新生代使用功能Parallel Scavenge 老年代将会使用Parallel Old收集器 开启 -XX:+UseParallelOldGC //CMS垃圾收集器(老年代) 开启 -XX:+UseConcMarkSweepGC //设置G1垃圾收集器 开启 -XX:+UseG1GC 2.
文章目录 前言一、灰色预测是什么?二、使用步骤1.使用条件2.以GM(1,1)为例(1)级比值检验(2)后验差比检验(3)模型拟合检验(4)模型残差检验(5)级比偏差检验 三 、总结1.代码总结2.公式总结 前言 灰色预测对原始数据进行生成处理来寻找系统变动的规律,并生成有较强规律性的数据序列,然后建立相应的微分方程模型,从而预测事物未来发展趋势的状况。
一、灰色预测是什么? 灰色预测是一种对含有不确定因素的系统进行预测的方法。 灰色预测通过鉴别系统因素之间发展趋势的相异程度,即进行关联分析,并对原始数据进行生成处理来寻找系统变动的规律,生成有较强规律性的数据序列,然后建立相应的微分方程模型,从而预测事物未来发展趋势的状况。 其用等时距观测到的反映预测对象特征的一系列数量值构造灰色预测模型,预测未来某一时刻的特征量,或达到某一特征量的时间
二、使用步骤 1.使用条件 这个应该是很清晰的,数据量少,四五个,然后类指数形式增长的,什么是类指数增长:就是一组数据累加后排列是否呈类指数增长,与且预测的时间不是很长,就可以用。 分为GM (1,1),GM (1,m),GM (n,m)分别用于一个自变量一个因变量,多个自变量一个因变量,多个自变量多个因变量。 灰色预测就是尽可能使用数据中含有的信息。 假设你有十组数据,需要预测接下来的三组数据,程序跑完,一般是有求残差的过程,看一看是不是小于0.1,如果每个数据点都是小于0.1,那这次灰色预测就是很好的。
注:
数据量较少的情况下使用;数据呈类指数增长;预测时间较短要先进行级比值检验后验差比检验模型拟合检验模型残差检验 2.以GM(1,1)为例 (1)级比值检验 (注:级比值介于区间[0.982,1.0098]时说明数据适合模型构建。)
从上表可知,针对某数据进行GM(1,1)模型构建,结果显示:级比值的最大值为1.010,在适用范围区间[0.982,1.0098]之外,意味着本数据进行GM(1,1)可能得不到满意的模型。但从数据来看,1.01非常接近于1.0098,因此有理由接着进行建模。
如下代码所示为数据级比检验:
m = length(A); JiBi = ones(1,m-1); for i =2:m JiBi(i-1) = A(i-1)/A(i); end max1 = max(JiBi); min1 = min(JiBi); FanWei = exp(2/(n+2))-exp(-2/(n+1)) if max1 - min1<FanWei disp(['数据通过级别检验']); else disp(['数据不通过级比检验']); end (2)后验差比检验 后验差比C值用于模型精度等级检验,该值越小越好,一般C值小于0.35则模型精度等级好,C值小于0.5说明模型精度合格,C值小于0.65说明模型精度基本合格,如果C值大于0.65,则说明模型精度等级不合格。
从上表可知,后验差比C值0.231 <=0.35,意味着模型精度等级非常好。
以下为发展系数、灰色作用量和C值代码:
%构造数据矩阵 B = [-C;ones(1,n-1)]; Y = A; Y(1) = []; Y = Y'; %Y进行了转置,C的公式求法与百度文库 发生了一些变化 % 使用最小二乘法计算参数 a(发展系数)和b(灰作用量) c = inv(B*B')*B*Y; %核心公式 c = c'; a = c(1); b = c(2); disp(['发展系数:',num2str(a)]); disp(['灰色作用量:',num2str(b)]); %预测后续数据 F = []; F(1) = A(1); %法二:方差比C检验 C = std(epsilon, 1)/std(A, 1); %方差函数std 按照列分 disp(['方差比C检验:',num2str(C)]); (3)模型拟合检验 上表格展示出模型的拟合值,以及向后12期的拟合数据情况,当然也可通过图形直观查看如下图,下图明显可以看出,往后时会一直下降,这是GM(1,1)模型的特征,其仅适用于中短期预测,因此向后1期和向后2期的数据具有价值,更多的预测数据需要特别谨慎对待。
虚拟机,Ubuntu操作系统,换成清华源 1、要先安装好VMware Tools工具(方便以后复制粘贴)。
2、先去清华大学镜像源官网找到自己安装的操作系统对应的镜像,网站如下:
https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/
我的是Ubuntu20.04版本的,如图:
先在终端使用下列代码,会进入一个编辑器。
sudo vi /etc/apt/sources.list 你需要将该文件内容先清空,先按Esc键,后打出冒号(:),输入:%d
这样就可以快速将文件中的全部内容清空
然后将网站上的代码复制一下,如图,然后将该段代码复制到该文件中去。
之后,按Esc键,输入: :wq (这具有保存退出的功能)
检验是否安装好清华源。
终端输入:sudo apt update
出现上图情况时,即完成了换源。
1.引言 最近是有总喜欢讨论算法题,因为他们在准备考研复试,为什么我不准备呢?这是一个悲伤的故事,刚好自己也有面试遇到只能使用C和C++的代码题,他们说这OJ平台相对简单一些,那些刷不来LeetCode可以试试这个,作为入门算法的跳板。体验体验写不出来或者找不到bug的那种感觉,避免入职第一天觉得顶不住压力,说实话,前端更偏向于业务,往往就是搜索——看看配置方式——总结或者深究原理(陈然很多时候我们都没有这最后一步,前端也就成了专业码砖的了)。一旦遇到某些bug解决不了或者某些功能没有实现的思路往往一下子上头。作为菜鸡,试了试浙江工商的这个还是挺适合我的,举出例子让前端编程弱的友友们了解一下吧。
2.网站 浙江工商大学OJ平台,链接:http://acm.zjgsu.edu.cn/,我们学校也有,大一也做了一些,但是没能坚持下去,算法需要足够的毅力才能有一些证书上的成果。当然也不必因为觉得算法不好而自卑,各有所长很正常,计算机越学越广。
3.题例一 题目简介:
思路上还是很好想出来的,关键是容错处理,首部和尾部的空格(可能是连续的无效空格),最后的解决思路是:
(1)首先排除首部的无效空格,然后再来计数;立一个flag,如果头部一直是空格,那么flag一直不变,出现字符反转flag,也就是有单词。
(2)中间计数:如果前面一个是空格,后一个不是空格,那么计数一次;
(3)后置处理:如果最开始设置的flag没有反转过,那就是都是空格,也就是没有单词;如果有单词,那么需要最后在计数的基础上+1,因为判断是基于单词空格判断的。
简单贴一下代码吧:
#include<bits/stdc++.h>//算法的万能头 using namespace std; int main() { string str; int num = 0; getline(cin, str); int len = str.length(); int flag = 0; for (int i = 0; i < len; i++) { //去掉首部的空格 if (!flag && str[i] == ' ') { continue; } else { flag = 1; if (i > 0 && (str[i - 1] == ' ' && str[i] !
文章目录 步骤一步骤二步骤三测试 以下是在Windows 10上使用VS2019配置CMake的步骤: 步骤一 首先需要安装CMake,可以在官网下载安装程序进行安装:https://cmake.org/files/v3.26/(镜像更快)
百度网盘:链接:https://pan.baidu.com/s/1kLVLY5pUVZGK4oWwUsBo9A?pwd=xdhy 提取码:xdhy
64位win10系统对应win64-x64,msi是安装版不需要配置环境变量,选择cmake-3.26.0-rc6-windows-x86_64.msi下载
步骤二 点击安装包,按步骤安装就可,不讲究。
步骤三 安装完成后重启下电脑,然后打开win+R打开管理器输入cmake --version要是出现cmake的版本号就说明cmake已经安装成功!
测试 安装完成后,启动VS2019,选择“文件”->“新建”->“项目”->“CMake”->“CMake项目”;在弹出的对话框中,选择“空白模板”,输入项目名称和路径,点击“创建”在“CMakeLists.txt”文件中添加需要的库和源代码文件,并进行相关配置,例如: cmake_minimum_required(VERSION 3.10) project(MyProject) find_package(PCL 1.2 REQUIRED) include_directories(${PCL_INCLUDE_DIRS}) link_directories(${PCL_LIBRARY_DIRS}) add_definitions(${PCL_DEFINITIONS}) add_executable(MyProject main.cpp) target_link_libraries(MyProject ${PCL_LIBRARIES}) 点击菜单栏中的“生成”->“生成”来生成项目生成完成后,在VS2019的“解决方案资源管理器”中可以看到生成的项目和相应的文件运行生成的可执行文件,测试项目是否能够正常运行
以上是基本的配置步骤,具体还需要根据不同的项目需求进行相应的配置。
本节内容主要介绍C++中的string
1. 简介 string是C++中的字符串类(字符串就是字符的序列),string其实是一个类型别名
using string = std::basic_string<char>; 头文件
#include <string> 2. 初始化方法 示例
#include <string> #include <iostream> template<typename T, typename Y> void print(T& t, Y& y) { std::cout<<t<< " is: \t" <<y<<std::endl; } int main(int argc, char *argv[]) { std::string str1; str1 = "C++"; std::string str2 = str1; //等号 std::string str3("C++"); //小括号 std::string str4{"C++"}; //大括号 std::string str5(5,'a'); //5个‘a’ std::string str6("python",2,4); //下标从2开始,长度为4 print("str1", str1); print("str2", str2); print("str3", str3); print("str4", str4); print("
一、原因分析
跨线程调用控件会出现这个错误的原因是因为:.NET禁止了跨线程调用控件, 否则谁都可以操作控件,最后可能造成错误。 所以不是在创建控件所在的线程内调用就会发生这样的错误。
二、解决办法
方法1:设置CheckForIllegalCrossThreadCalls =false 是能去掉这个检查的,但是这不是标准的作法.
方法2:定义一个委托(delegate),委托(delegate)可以将参数与方法传递给控件所在的线程,并由控件所在的线程执行,通过Invoke来调用,这样可以完美的解决此类问题。
Action action = () => { TimeBox.Text = TimeString; ResultBox.Text = hv_ResultStr; DisplayImageHalconWindow(AcqImage, GrayImage); DisplayImageHalconWindow(ThresholdImage, MeanImage); }; Invoke(action); 三、总结
在控件的线程中遇到阻塞时可以通过创建另一个线程来解决界面的阻塞问题,例:new Thread(ImageDealThread).Start();将控件所需要处理的事件封装到一个函数里面,通过线程进行调用,跨线程访问控件可以通过定义一个委托(delegate)来将参数与方法传递给控件所在的线程,再通过Invoke来调用。
错误之处,欢迎大家指出!
1 建立文件夹
cd /opt mkdir software 下载最新的包,并解压 https://prometheus.io/download/
下载 curl -LO https://github.com/prometheus/node_exporter/releases/download/v0.18.1/node_exporter-0.18.1.linux-amd64.tar.gz 3.解压
tar -xvf node_exporter-0.18.1.linux-amd64.tar.gz 移动二级制文件到 /usr/local/bin/下 sudo mv node_exporter-0.18.1.linux-amd64/node_exporter /usr/local/bin/ 5.创建用户去启动
sudo useradd -rs /bin/false node_exporter 6.在systemd下创建脚本文件
sudo vi /etc/systemd/system/node_exporter.service 内容如下:
[Unit] Description=Node Exporter After=network.target [Service] User=node_exporter Group=node_exporter Type=simple ExecStart=/usr/local/bin/node_exporter [Install] WantedBy=multi-user.target 7.加载守护进程 sudo systemctl daemon-reload 8.启动
sudo systemctl start node_exporter 9.查看状态
sudo systemctl status node_exporter 10 查看:http://:9100/metrics
结构型模式描述如何将类或对象按某种布局组成更大的结构,它分为类结构型和对象结构型模式,前者采用继承机制来组织接口和类,后者采用组合或聚合来组合对象。
由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。
结构型模式分为以下7种:
代理模式;适配器模式;装饰者模式;桥接模式;外观模式;组合模式;享元模式。 1、代理模式 1.1、概述 由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成,而动态代理代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种。
1.2、结构 代理(Proxy)模式分为三种角色:
抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。 1.3、静态代理 我们通过案例来感受一下静态代理。
【例】火车站卖票
如果要买火车站的票,需要去火车站买票,坐车到火车站,排队等一系列的操作,显然比较麻烦。而火车票在多个地方都有代售点,我们就进去代售点卖票就方便多了。这个例子其实就是典型的代理模式,火车站是目标对象,代售点是代理对象。
// 抽象主题类:卖火车票的接口 interface SellTickets { void sell(); } // 具体主题类:火车站类 class TrainStation implements SellTickets { @Override public void sell() { System.out.println("火车站卖票"); } } // 代理类:代售点类 class ProxyPoint implements SellTickets { // 声明火车站类对象 private TrainStation trainStation = new TrainStation(); @Override public void sell() { System.out.println("代理点收取一些服务费用"); trainStation.sell(); } } public class Client2 { public static void main(String[] args) { // 创建代售点类对象 ProxyPoint proxyPoint = new ProxyPoint(); // 调用方法进行买票 proxyPoint.
参考文档:https://www.hivemq.com/mqtt-essentials/
MQTT是物联网(IoT)最常用的消息传输协议。MQTT是MQ遥测传输的缩写。该协议是一套规则,定义了物联网设备如何通过互联网发布和订阅数据。MQTT用于物联网和工业物联网(IIoT)设备之间的信息传递和数据交换,如嵌入式设备、传感器、工业PLC等。该协议是事件驱动的,使用发布/订阅(Pub/Sub)模式连接设备。发送方(Publisher)和接收方(Subscriber)通过主题(Topic)进行通信,彼此之间是解耦的。它们之间的连接是由MQTT代理处理的。MQTT代理过滤所有传入的消息,并将它们正确地分发给订阅者。
1、MQTT介绍 1.1、MQTT 简介 “MQTT是一个客户端服务器发布/订阅消息的传输协议。它是轻量级的、开放的、简单的,而且设计得很容易实现。这些特点使它在许多情况下都是理想的选择,包括受限制的环境,如机器对机器(M2M)和物联网(IoT)背景下的通信,其中需要较小的代码足迹和/或网络带宽是有优势的。”—— MQTT 3.1.1规范
MQTT规范的摘要很好地描述了MQTT的内容。它是一个非常轻量级的二进制协议,由于其最小的数据包开销,与HTTP等协议相比,MQTT在电线上传输数据时表现出色。该协议的另一个重要方面是,MQTT在客户端非常容易实现。易用性是MQTT发展过程中的一个关键问题,并使其成为当今资源有限的受限设备的完美选择。
1.2、一点点历史 MQTT协议是由Andy Stanford-Clark(IBM)和Arlen Nipper(Arcom,现在的Cirrus Link)于1999年发明的。他们需要一个最小电池损耗和最小带宽的协议,以便通过卫星与石油管道连接。这两位发明家为未来的协议指定了几个要求:
简单的实现;服务质量的数据交付;轻量级,带宽高;数据无关紧要;持续的会话感知。 这些目标仍然是MQTT的核心。然而,该协议的主要焦点已经从专有的嵌入式系统转变为开放的物联网(IoT)用例。这种焦点的转移造成了很多关于MQTT的缩写代表什么的混乱。简短的回答是,MQTT不再被认为是一个首字母缩写。MQTT只是该协议的名称。
较长的答案是,前者的缩写代表MQ遥测传输。
"MQ "指的是MQ系列,这是IBM开发的一个支持MQ遥测传输的产品。当Andy和Arlen在1999年创建他们的协议时,他们用IBM的产品来命名它。许多消息来源将MQTT错误地标记为一个消息队列协议。这根本不是事实。MQTT不是一个传统的消息队列解决方案(尽管在某些情况下有可能对消息进行排队,这一事实我们将在接下来的文章中详细讨论)。在接下来的十年里,IBM在内部使用该协议,直到他们在2010年将MQTT 3.1作为免版税版本发布。从那时起,欢迎每个人都来实现和使用该协议。
我们在2012年开始认识了MQTT,并在同年建立了第一个版本的HiveMQ。2013年,我们向公众发布了HiveMQ。随着协议规范的发布,IBM为Eclipse基金会新成立的Paho项目贡献了MQTT客户端的实现。这些事件对该协议来说绝对是一件大事,因为如果没有一个支持性的生态系统,几乎没有机会广泛采用。
1.3、OASIS标准和当前版本 在最初发布约3年后,宣布MQTT将在OASIS(一个以推进标准为目的的开放组织)的羽翼下实现标准化。AMQP、SAML和DocBook只是之前发布的OASIS标准中的几个。标准化过程花了大约1年时间。2014年10月29日,MQTT成为正式批准的OASIS标准。从3.1到3.1.1的小版本变化表明,对前一个版本的修改很少。有关这些变化的详细信息,请参见我们关于3.1.1的优势的博文。
2019年3月,OASIS批准了新的MQTT 5规范。这个新的MQTT版本为MQTT引入了部署在云平台上的物联网应用所需的新功能,以及那些需要更多的可靠性和错误处理来实现关键任务的信息传递。要了解更多关于MQTT 5的信息,请查看我们的MQTT 5精华系列博客。
我们强烈建议使用MQTT 5。
2、发布和订阅基础知识 2.1、MQTT 发布/订阅模式 MQTT发布/订阅模式(也称为pub/sub)为传统的客户端-服务器架构提供了一个替代方案。在客户端-服务器模式中,客户端直接与端点进行通信。pub/sub模式将发送消息的客户端(发布者)与接收消息的客户端(订阅者)解耦。发布者和订阅者从不直接联系对方。事实上,他们甚至不知道对方的存在。他们之间的联系由第三个组件(经纪人)处理。经纪人的工作是过滤所有传入的消息,并将它们正确地分发给订阅者。因此,让我们深入了解一下发布/订阅的一些一般方面(我们将在一分钟内谈论MQTT的具体内容)。
pub/sub最重要的方面是消息的发布者与接收者(订阅者)的解耦。这种解耦有几个方面:
空间解耦。发布者和订阅者不需要互相认识(例如,不交换IP地址和端口)。时间解耦。发布者和用户不需要在同一时间运行。同步解耦。在发布或接收期间,两个组件上的操作都不需要中断。 总之,MQTT的pub/sub模型取消了消息的发布者和接收者/订阅者之间的直接通信。代理商的过滤活动使得控制哪个客户/用户收到哪个消息成为可能。解耦有三个层面:空间、时间和同步。
2.2、可扩展性 ** MQTT Pub/Sub的扩展性比传统的客户-服务器方法好**。这是因为代理上的操作可以高度并行化,消息可以以事件驱动的方式处理。消息缓存和消息的智能路由往往是提高可扩展性的决定性因素。尽管如此,扩展到数百万的连接是一个挑战。这样高的连接量可以通过集群的经纪人节点来实现,使用负载均衡器将负载分配到更多的单个服务器上。(这个话题超出了当前文章的范围,我们将在另一篇文章中介绍)。
2.3、信息过滤 很明显,MQTT代理在发布/订阅过程中起着关键的作用。但是,经纪人是如何过滤所有的消息,使每个订阅者只收到感兴趣的消息的呢?正如你将看到的,代理有几个过滤方案:
方案1-基于主题的过滤:这种过滤是基于作为每个消息一部分的主题或话题。接收客户端向经纪人订阅感兴趣的主题。从那时起,经纪人确保接收客户端获得所有发布在订阅主题上的消息。一般来说,主题是具有分层结构的字符串,允许根据有限的表达方式进行过滤。方案2-基于内容的过滤:在基于内容的过滤中,经纪人根据特定的内容过滤语言来过滤消息。接收客户端订阅他们感兴趣的消息的过滤查询。这种方法的一个重要缺点是,消息的内容必须事先知道,而且不能加密或轻易改变。方案3-基于类型的过滤:当使用面向对象的语言时,基于消息(事件)的类型/类别进行过滤是一种常见的做法。例如,一个用户可以监听所有的消息,这些消息的类型是Exception或任何子类型。 当然,发布/订阅不是每个用例的答案。在你使用这种模式之前,有几件事你需要考虑。发布者和订阅者的解耦是pub/sub的关键,它本身也带来一些挑战。例如,你需要事先了解发布的数据是如何结构化的。对于基于主题的过滤,发布者和订阅者都需要知道要使用哪些主题。另一件需要注意的事情是信息传递。发布者不能假设有人在收听所发送的消息。在某些情况下,有可能没有订阅者阅读某条消息。
2.4、MQTT 的主要特点 现在我们已经探讨了一般的发布/订阅模型,让我们具体关注一下MQTT。根据你想要实现的目标,MQTT体现了我们所提到的发布/订阅的所有方面:
MQTT在空间上将发布者和订阅者解耦。为了发布或接收消息,发布者和订阅者只需要知道经纪商的主机名/IP和端口。MQTT在时间上进行解耦。尽管大多数MQTT用例都是以近乎实时的方式传递消息,但如果需要的话,经纪人可以为不在线的客户存储消息。(要存储消息必须满足两个条件:客户端已经连接了一个持久的会话,并且订阅了一个服务质量大于0的主题)。MQTT以异步方式工作。因为大多数客户端库都是异步工作的,并且是基于回调或类似的模型,任务在等待消息或发布消息时不会被阻塞。在某些用例中,同步化是可取的,也是可能的。为了等待某个消息,一些库有同步的API。但流程通常是异步的。 另一件应该提到的事情是,MQTT在客户端特别容易使用。大多数pub/sub系统的逻辑都在代理方,但MQTT在使用客户端库时确实是pub/sub的精髓,这使得它成为小型和受限设备的轻量级协议。
MQTT使用基于主题的消息过滤。每条消息都包含一个主题(topic),经纪人可以用它来决定订阅的客户端是否能得到该消息。请参阅MQTT要点的第5部分,了解更多关于主题的概念。如果需要,你也可以用HiveMQ MQTT代理和我们的自定义扩展系统来设置基于内容的过滤。
为了应对pub/sub系统的挑战,MQTT有三个服务质量(QoS)级别。你可以很容易地指定一个消息被成功地从客户端传递给代理,或从代理传递给客户端。然而,有可能没有人订阅这个特定的主题。如果这是一个问题,经纪人必须知道如何处理这种情况。例如,HiveMQ MQTT代理有一个插件系统,可以解决这种情况。你可以让经纪人采取行动,或者简单地将每条消息记录到数据库中进行历史分析。为了保持分层主题树的灵活性,必须非常仔细地设计主题树,并为未来的用例留下空间。如果你遵循这些策略,MQTT是生产设置的完美选择。
2.5、MQTT 与消息队列的区别 对于MQTT这个名字,以及该协议是否以消息队列的形式实现,有很多人感到困惑。我们将尝试对这个话题进行一些说明,并解释其中的区别。在上一篇文章中,我们提到MQTT指的是IBM的MQseries产品,与 "消息队列 "没有关系。不管这个名字来自哪里,了解MQTT和传统的消息队列之间的区别是非常有用的。
当你使用一个消息队列时,每个传入的消息都被储存在队列中,直到它被一个客户(通常称为消费者)取走。如果没有客户端拿起该消息,该消息仍停留在队列中,等待被消费。在消息队列中,消息不可能不被任何客户端处理,就像在MQTT中,如果没有人订阅一个主题一样。
一个消息只被一个客户消费。另一个很大的区别是,在传统的消息队列中,一个消息只能被一个消费者处理。负载是在一个队列的所有消费者之间分配的。在MQTT中,行为则完全相反:每个订阅主题的订阅者都能得到消息。
队列是命名的,必须明确创建队列 队列比主题要严格得多。在使用队列之前,必须用一个单独的命令明确地创建队列。只有在队列被命名和创建之后,才有可能发布或消费消息。相比之下,MQTT主题非常灵活,可以即时创建。
3、客户端、代理和连接的建立 下面是对核心概念的快速回顾:
发布/订阅将发送消息的客户端(发布者)与接收消息的客户端(订阅者)解耦。MQTT使用消息的主题(topic)来决定哪条消息到哪个客户端(订阅者)。主题是一个分层结构的字符串,可用于过滤和路由消息(更多细节)。 我们的上一篇文章给了你一个关于发布/订阅模型的高层观点,以及它与传统的消息队列有什么不同。这篇文章采取了一种实用的方法,并塞满了关于MQTT的基本知识:MQTT客户端和代理的术语定义,MQTT连接的基本知识,带有参数的连接消息,以及通过代理的确认建立连接。
3.1、MQTT 客户端和 MQTT 代理(Broker)介绍 因为MQTT将发布者和订阅者解耦,所以客户端连接总是由一个经纪人处理。在我们讨论这些连接的细节之前,让我们清楚地了解一下我们所说的客户端和经纪人是什么意思。
源代码:
#include <stdio.h> int main() { double e=0.0; int i=1,j=1,t=1; while(1.0/t >= 1e-5) { e=e+1.0/t; t=t*j; j++; } printf ("计算结果为:%lf\n",e); return 0; } 运行结果:
目录 方法一、 _access函数判断文件夹或者文件是否存在方法二、qt 使用PathFileExists判断文件文件夹是否存在,CreateDirectory创建文件夹2.1 判断文件文件夹是否存在函数原型2.2 创建文件夹函数原型示例一示例二 方法一、 _access函数判断文件夹或者文件是否存在 函数原型Check_return _CRTIMP int __cdecl _access(In_z const char * _Filename, In int _AccessMode);备注参数 filename文件夹路径或者文件路径。例如G:\BaiduNetdiskDownload参数 mode00 判断是否存在 02 判断写入权限
04 判断读取权限
06 判断执行权限 成功返回 0,否则返回 -1。
所属头文件:
#include "io.h" 实例:
// crt_access.c // compile with: /W1 // This example uses _access to check the file named // crt_ACCESS.C to see if it exists and if writing is allowed. #include <io.h> #include <stdio.h> #include <stdlib.
提示:vue2 + elementUi(适用于table不使用fixed固定列,否则会错位,修复错位方法在下篇)
前言 需求:在使用el-table中,当每页数据过多时浏览器会自动产生纵向滚动条,拖动后表头也看不到了,当表头过长后,也会产生横向滚动条,但是横向滚动条固定在table最底部,不利于操作。
思路:利用自定义指令中的el找出table的dom元素,获取到视窗总高度,获取到table离视窗上面的高度,获取到指令中回传想设置的离底部的高度,计算后获得table高度,并设置css,再通过resize监听动态获取高度,设置高度。
一、使用步骤 1. 在src下面创建一个directive文件夹,再创建index.js和tableHeight.js tableHeight.js 代码如下:
import { addResizeListener, removeResizeListener } from 'element-ui/src/utils/resize-event' // 设置表格高度 const doResize = async (el, binding, vnode) => { // 获取表格Dom对象 const { componentInstance: $table } = await vnode // 获取调用传递过来的数据 const { value } = binding // if (!$table.height) { // throw new Error(`el-$table must set the height. Such as height='100px'`) // } // console.log($table, '$table$table$table$table') // 获取距底部距离(用于展示页码等信息) const bottomOffset = (value && value.
文章目录 前言一、如何在VisualStudio2019中新增项目版本信息二、在程序中调用项目版本信息1.引入库version.lib1.1.通过vs自带的属性页引入库1.2.手动引入库 2.新增版本信息读取类3.调用类获取信息 总结 前言 本文主要讲述如何在Visual Studio 2019 以及Qt结合的开发项目中,新增版本信息到资源;并且可以通过代码读取资源存储的版本信息。
一、如何在VisualStudio2019中新增项目版本信息 切换到解决方案视图中
在解决方案名称上右键
添加
资源
选择Version,点击新建
按照自己的公司,版权,版本信息填写并保存编译
二、在程序中调用项目版本信息 为了保证整个项目的统一性,建议版本维护就在这里维护,如果项目中,界面里要调用到相关信息,那么就通过如下操作对里面的信息进行读取
1.引入库version.lib 1.1.通过vs自带的属性页引入库 切换到属性管理器页右键Debug/Release,添加新项目属性表随便起个名在链接器-输入-附加依赖项中添加version.lib应用并确定 1.2.手动引入库 代码如下(示例):
#pragma comment(lib, "version.lib") 2.新增版本信息读取类 新增头文件
#pragma once #include <QObject> #include <windows.h> #include <tchar.h> class VersionUpdate { public: QString product_name = ""; QString company_info = ""; QString copyright_info = ""; QString version_info = ""; QString VersionUpdate::GetVersion() { int nMaxPathName = 4096; // Max length of file name/path TCHAR* pBuffer; UINT nItemLength; void* pData, * lpBuffer; QString sVersion; DWORD dwInfoSize, dwHandle; VS_FIXEDFILEINFO* pFileInfo; // Get the file path and name pBuffer = new TCHAR[nMaxPathName]; GetModuleFileName(NULL, pBuffer, nMaxPathName - 1); // Get File Version Info size dwInfoSize = GetFileVersionInfoSize(pBuffer, &dwHandle); if (dwInfoSize > 0) { pData = new TCHAR[dwInfoSize]; if (GetFileVersionInfo(pBuffer, dwHandle, dwInfoSize, pData)) { //获取产品名称 if (VerQueryValue(pData, _T("
TP传输工具是专门设计用于通过网络在电脑和服务器之间传输文件的软件。这些FTP传输工具支持 FTP、SFTP、HTTP/HTTPS 等协议。许多FTP传输工具具有拖放功能,以便将文件从一个地方复制到另一个地方。可以使用这些应用程序快速同步本地和远程文件夹。
以下是为Windows和Mac精心挑选的最佳 FTP传输工具和程序列表,以及它们的流行功能和网站链接。该列表包含开源和商业软件。
(1)FTP传输工具-GoodSync
GoodSync是一个备份和文件同步工具。该软件可用于在计算机与存储设备之间或计算机与服务器之间同步文件。它使用户能够运行并行线程以实现文件传输速度。
主要特点是:可以轻松传输实时数据,它是好的FTP传输工具之一,无需用户交互即可执行自动计划和实时备份。使用 AES-256 加密文件。它可以检测重命名或从一个位置移动到另一个位置的文件。可以控制带宽速度。提供执行的操作日志和更改报告,可以修复访问被拒绝的错误。FTP传输工具可以通过 MD5 比较两个文件,可以指定可移动驱动器的路径。
(2)FTP传输工具-FileZilla
FileZilla是一个免费的FTP解决方案,用于通过网络传输数据。该软件可帮助轻松过滤文件名。它是适用于Windows的FTP传输工具之一,提供拖放功能以将所需文件从本地计算机复制到服务器。
主要特征:可以轻松浏览同步库。它提供远程文件搜索,比较目录是可能的,可以轻松编辑远程文件,提供多种语言版本,这个免费的FTP传输工具支持 FTP、SSH 文件传输协议 (SFTP) 和 FTP over SSL/TLS (FTPS),可以配置文件传输的速度,提供网络配置向导的免费FTP传输工具之一。
(3)FTP传输工具-solarwinds
Serv-U 文件传输协议服务器可帮助轻松地从Web和移动设备传输文件。可以快速添加和管理用户和组。可以有效地进行监控和故障排除,以快速解决问题。
主要特点:允许您轻松传输多个大文件,简单的文件传输管理,能够避免 DMZ 网络中的静态数据,可以管理文件传输设置和权限,可免费试用。
(4)FTP传输工具-Commander One
Commander One 是一个 MAC FTP传输工具。它提供了一个方便的选项,可以将文件从一台服务器复制到另一台服务器、删除等。该FTP传输工具提供对FTP协议的全面支持。它可以帮助用户同时建立多个连接。
主要特征:可以将 FTP 服务器映射为本地驱动器,能够链接整个 Amazon S3(Amazon 简单存储服务)帐户,安装多个 Dropbox 帐户,可以使用 Google 文档和表格,支持Mac、云存储和远程服务器之间的加密文件,压缩机提取档案没有任何麻烦,方便选择文件,提供对网络上共享计算机的访问。
(5)FTP传输工具-WinSCP
WinSCP 是 Microsoft Windows 的FTP传输工具。它是 Windows好用的FTP传输工具之一,能够在本地系统和远程服务器之间顺利复制任何文件。该FTP传输工具具有主要的文件管理器和文件同步功能。
主要特征:提供易于使用的图形用户界面 (GUI),此 SFTP Windows 客户端支持脚本和任务自动化。具有集成的文本编辑器,WinSCP界面可以翻译成多种语言,提供命令行界面,通过文件加密确保安全,端口转发是可能的,可以以独立的可移植可执行文件的形式下载。
(6)FTP传输工具-Transmit
Transmit 是一种FTP传输工具,可帮助您在各种服务器上上传、下载和管理文件。它是适用于 Mac的最佳FTP传输工具之一,具有极其易于使用的 UI。此文件传输协议工具可用于 macOS。
主要特点:改进了远程 URL 复制功能,支持 Amazon S3 API V4 的最佳 FTP 客户端之一。
实现目标:h5实现位置的搜索,地图任意选点,获取经纬度及位置信息;
第一步:安装 @amap/amap-jsapi-loader插件:npm i @amap/amap-jsapi-loader --save;
第二步:
<template> <!-- 地图选择位置,包括地图点击选点,搜索 --> <div class="StationMap"> <van-nav-bar title="选择具体问题位置" fixed placeholder safe-area-inset-top left-text="返回" left-arrow @click-left="close" /> <!-- 高德关键字搜索,个人每天限制100次调用,企业限值1000次 --> <div class="searchArea"> <van-search v-model="searchVal" show-action label="地址" placeholder="请输入具体位置" @search="onSearch"> <template #action> <div @click="onSearch">搜索</div> </template> </van-search> <van-dropdown-menu v-if="showsearchResult"> <van-dropdown-item v-model="checkedVal" :options="positionArr" @change="searchPosition" /> </van-dropdown-menu> </div> <!-- 地图容器 --> <div id="containerMap"></div> </div> </template> <script> import { reactive, toRefs, onMounted } from 'vue'; import AMapLoader from '@amap/amap-jsapi-loader'; import pointImg from '@/assets/images/common/position.
前不久偶然发现微信里有一个变量叫做 __wxConfig,解决了这个问题,但是微信真的坑,你甚至在官方搜不到这个变量 = =,今天和大家分享一下
console.log(__wxConfig); //全局值 经过测试得到 envVersion 的具体键值有:develop(开发版)trial(体验版)release(正式版) 获取开发状态,判断获取请求url
// 全局参数 const env = __wxConfig.envVersion const baseUrls= { develop: '开发环境url2', release: '正式环境url', trial: '测试环境url' } // 判断开发状态,获取相关url isDevelopmentStatusUrl(){ const env = __wxConfig.envVersion; return baseUrls[env] || API_URL; }
参考:tensorflow-gpu 2.6.0版本安装教程
史上最强tensorflow2.6.0安装教程
更新CUDA驱动 此处可参考:如何在windows上 安装&更新 显卡的驱动
建议将cuda driver(显卡驱动)升级到最新版本,这样cuda runtime版本可以有更多选择
(1)进入英伟达官网下载驱动:https://www.nvidia.cn/Download/index.aspx?lang=cn
选择GPU型号对应的NVIDIA驱动(可在“任务管理器”查看)
“产品系列”中,(Notebook) 表示为笔记本上的显卡驱动;下载类型选择默认的Game Ready 驱动程序
点击上图中的“搜索”,进入下图界面后点击“下载”(跳转后点击“同意并开始下载”)
下载完成后,双击exe运行安装,安装位置选择默认即可
安装完成后,会进入NVIDIA图形驱动程序界面,
依次点击“同意并继续”--> "精简(推荐)" 进入安装,
安装完后,最后的界面全部取消勾选
(2)打开命令行cmd,使用 nvidia-smi 查看 cuda driver 版本
2. 安装cuda runtime 此处可参考:详细讲解如何在win10系统上安装多个版本的CUDA
(1)进入官网选择适合的cudatoolkit版本:https://developer.nvidia.com/cuda-toolkit-archive
注意cuda runtime版本不应该超过cuda driver版本
选择exe(local) 下载本地,安装程序可默认安装在C盘,CUDA安装位置可自己选择(D盘)
(2)打开命令行cmd,使用 nvcc -V 查看cuda runtime 版本
(3)安装cudnn
进入官网下载cudatoolkit对应版本的cudnn(下载需注册):https://developer.nvidia.com/rdp/cudnn-archive
将下载的zip文件解压,解压后将其中的bin、include、lib三个文件,复制粘贴到cudatoolkit的安装位置
(4)查看cudnn版本
打开cudatoolkit安装路径下的\include\cudnn_version.h文件
cudnn版本即为cudnn_majar . cudnn_minor . cudnn_patchevel
(5)设置环境变量
当存在多个cudatoolkit版本时,下图Path中需将当前使用的版本放在其他版本前面,
3. 安装tensorflow2.6.0 (1)打开 Anaconda Prompt,创建虚拟环境
conda create -n tensorflow python=3.8 (2)激活虚拟环境
conda activate tensorflow (3)安装tensorflow-gpu版本(已集成keras),使用豆瓣镜像源加速
安装某个包出现以下情况:
EnvironmentNotWritableError: The current user does not have write permissions to the target environment.
environment location: E:\anaconda
解决方法一:找到此文件夹,右击属性-安全-修改成完全控制
解决方法二:上述方法没用,用管理员身份打开anaconda prompt,在相应环境下下载包即可
在微服务架构中,分布式通信、分布式事务、分布式锁等问题是亟待解决的几个重要问题。 Spring Cloud是一套完整的微服务解决方案,基于 Spring Boot 框架。确切的说,Spring Cloud是一个大容器(而不是一个框架),它可以将通过集成一些好的微服务框架,从而简化开发者的代码量。
Dubbo 是阿里开源的分布式通信框架,专注于通信服务治理,类似于Spring Cloud中 Ribbon、 Hystrix、 Feign等核心组件的功能。
下面,我们着重来聊下这两种处理方式有何不同。
01 协议处理 1)Spring Cloud更加优雅简单
Feign使用Http进行传输。
Feign 集成了Ribbon,并且嵌入了Spring cloud全家桶 ,通过简单配置 ,就能在分布式里面实现服务间的调用,类似于Bean 调用。
2)Dubbo方式更灵活
Dubbo协议可选,大部分情况使用Dubbo传输协议,也可以使用http协议。
从协议层选择看,Dubbo是配置化的,更加灵活。
Dubbo 协议更适合小数据高并发场景。
02 性能方面 1)Spring Cloud性能调优
Feign 在高并发场景下,通常需要进行如下性能优化,有明显瓶颈,需要改造。
· 调整服务容器到 UnderTow ,在负载大的情况下Undertow 的性能有提高;
· 曾有同学表示将HTTPURLConnection 改成 Httpclient /Okhttp,这样可以优化性能,其实单次调用性能Httpclient差很多,HttpClient 因为封装了很多方便开发者处理的方法,性能比HTTPURLConnection差,改进同时Httpclient 需要设置复用连接池,效果可见一般;
· 开启Gzip;
· Feign中HttpMessageConverters 默认使用jackson2方式进行序列化和反序列化,可以将其改造为ProtoBuf,降低Cpu 损耗并且响应时间也降低。
2)Dubbo性能调优
主要是配置而无需改造。
03 负载均衡 1)Ribbon 的负载均衡策略
· 随机;
· 规则轮询;
· 空闲策略;
· 响应时间策略。
Feign默认使用Ribbon作为负载均衡的组件,Ribbon需要进行全局配置,个性化配置比较麻烦。
为了提高系统吞吐量,系统使用线程池越来越多。由于缺乏对线程池的统一监控手段,运营人员不知道线程池的具体运行情况,不利于线程池的性能调优。 开发线程池监控系统,对系统中的线程池进行统一监控。 详细代码参见utils
(一)线程池运行时数据的收集与展示
定义线程池统计数据接口ExecutorMonitorData,用于获取线程池的运行时数据,包括所属服务、线程池名称、线程池的唯一标识(线程池一般随系统启动而启动,随系统关闭而关闭)、核心线程数、当前线程数、历史最大线程、最大线程数、当前活跃线程数、最大空闲时间、当前任务数、已完成数量、任务执行总时间、任务执行最长时间、最短时间、排队最初时间、排队最短时间、执行超时次数、异常次数、排队超时次数、拒绝次数、阻塞队列、线程工厂、拒绝策略、启动时间。 import java.util.Date; import java.util.concurrent.TimeUnit; /** * 定义监控数据接口 */ public interface ExecutorMonitorData { /** * 线程池启动时间 */ Date getStartTime(); /** * 线程池所在服务 */ String getService(); /** * 线程池名字,每个线程池有一个唯一的名字,比如HttpRequest、DbExecutor */ String getPoolName(); /** * 线程池的唯一标识,因为线程池可能因为重启等因素被关闭,但是要唯一区别一个线程池,所以不能使用{@link ExecutorMonitorData#getPoolName()}, * 建议的格式为{@link top.jfunc.common.thread.monitor.generator.CommonIdentifierGenerator} */ String getIdentifier(); /** * 当前核心线程数 */ int getPoolSize(); /** * 配置的核心线程数 */ int getCorePoolSize(); /** * 历史到达最大线程数 */ int getLargestPoolSize(); /** * 配置的最大线程数 */ int getMaximumPoolSize(); /** * 当前活跃线程数 */ int getActiveCount(); /** * 线程最大空闲时间 */ long getKeepAliveTime(TimeUnit timeUnit); /** * 是否允许核心线程空闲回收 */ boolean allowsCoreThreadTimeOut(); /** * 当前任务数 */ long getTaskCount(); /** * 已完成任务数 */ long getCompletedTaskCount(); /*BlockingQueue<Runnable> getQueue(); ThreadFactory getThreadFactory(); RejectedExecutionHandler getRejectedExecutionHandler();*/ /** * 阻塞队列容量 */ int getQueueCapacity(); /** * 阻塞队列当前数量 */ int getQueueSize(); /** * 阻塞队列的类名 */ String getQueueClass(); /** * 线程工厂的类名 */ String getThreadFactoryClass(); /** * 拒绝策略的类名 */ String getRejectedExecutionHandlerClass(); /** * 任务执行总时间,依赖于{@link top.
入网小助手IsAgent卸载
暑期实习的时候装了公司的入网小助手,今天卸载的时候突然发现要密码。
卸载思路来源于
上网小助手IsAgent卸载程序破解
https://www.52pojie.cn/thread-1428177-1-1.html
(出处: 吾爱破解论坛)
转载于:http://www.phpheidong.com/blog/article/127152/4904c9a37f068c09815c/
1.打开任务管理器找到IsaHelp进程,然后右击打开文件所在位置
2.接下来用Ollydbg打开这个文件(Ollydbg需要管理员权限运行)
打开时要注意加上-remove参数
3.打开后在主窗口右击进行查找参考文本,如图:
4.拖动滚动条找到如下图所示的文字信息,并双击这一行
5.双击跳转到主窗口,我们可以看到选中行上面有一条0F85 7C000000 jnz IsaSetup.00402E13指令
jnz是汇编条件转移指令,那么我们将条指定改为jz是不是就变成了与原来相反的结果,即不需要验证码。双击这条指令后会弹出窗口在输入框里将jnz改为jz,并点击汇编按钮,点完按钮后窗口不会消失需要点取消。
完成操作后会发现这一条变红了,jnz也变成了je
按F9(调试→汇编)运行试一下,经过几秒的等待果然出现了我们想要的结果
点击确定就可以进行卸载了,卸载后可能会提示重启系统。
入网小助手IsAgent卸载
1.背景 使用Git做项目的版本控制时,在版本系统中会有很多的代码的提交记录,我们使用git log命令就会得到如下图中的提交记录:
当我们的项目比较简单,规模较小、开发人员也只有一两个的时候,其实可以不用定义代码的提交记录模板,但是当我们的项目开始变得庞大,有很多的开发者都在参与开发的时候,我们会发现每个人提交的信息都是千奇百怪的,出现了一个问题,要定位具体的提交时更是如大海捞针。特别痛苦。所以Git提供了代码提交记录模板,和对提交记录模板的验证,让每个提交代码的开发者按照模板填写提交的信息,提交后再验证下开发者是否按照模板的要求填写提交信息,如果没有就不让其执行接下来的git push命令。
2.解决方案 2.1 技术可行性 2.1.1 如何实现 其实当我们创建了一个Git的本地仓库后,项目的根目录下看到一个.git文件夹,在文件夹下的hooks目录下有很多的.sample 为后缀的文件,如下图所示
这些文件就是我们要改造的脚本,这个以.sample后缀结束的脚本文件是不会执行的,如果需要执行,我们需要去掉.sample后缀。我们要实现的功能是定义Git提交模板和校验模板的正确性。所以我们可以参考prepare-commit-msg.sample(提交模板)和commit-msg.sample(验证模板)完成我们的功能,修改完这个模板后我们就可以使用模板了,当我们需要使用命令git commit 提交代码时,在出现的提交信息编辑器中会出现我们在prepare-commit-msg脚本中定义好的模板,我们填写完模板后保存模板,这时会使用commit-msg脚本对模板做校验。这样的话我们的本地提交代码就能使用我们定义好的模板了。
2.1.2 如何同步配置到项目中其他开发者 现在还有一个问题,就是这些配置都是在我们的本地,项目中的其他开发者并没有这个环境,我们如果让他们去配置显然不合适,因为有的人可能不会搭理你。所以我们需要做到让开发者无感知的就装上了我们的环境,原理其实就是我们将模板提交到代码仓库中,然后通过脚本将配置的模板拷贝到用户的".git/hooks"目录下,当用户触发某个操作时,就执行脚本。本文我们以Android项目为例子,使用Gradle脚本,当用户执行构建操作的时候,我们执行配置提交模板的脚本
2.2 实现方案 2.2.1 提交模板的脚本示例 在.git/hooks目录下,复制prepare-commit-msg.sample文件,重命名为prepare-commit-msg(注意这里没有“.sample后缀名”),我们定义一个模板:
项目名称: [MountTai] 部门名称: [] 禅道BUGID: [无]
原因分析: {}
解决方案: {}
prepare-commit-msg:(脚本是用perl语言和shell语言搭配写的,比较简单就不细讲了),逻辑就是在开发者进入编辑器之前,往编辑器写入我们的模板。这样编辑器打开后显示的就是我们写的模板啦。
#!/bin/sh COMMIT_MSG_FILE=$1 COMMIT_SOURCE=$2 SHA1=$3 case "$2,$3" in merge,) /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; ,|template,) /usr/bin/perl -i.bak -pe 'print "项目名称: [MountTai] 部门名称: [] 禅道BUGID: [无]\n #部门名称: Android开发部 / 三维软件部 \n\n原因分析: {}\n解决方案: {}\n"
目录 前言一、功能与需求分析二、详细设计与实现1、data包(1)Data+DataBase(2)NaPa+NamePassword 2、operation包(1)操作接口(2)Resident用户功能(3)Simper用户功能(4)Checker用户功能 3、user包(1)User类(2)Resident类(3)Samper类(4)Checker类 4、Main-系统逻辑主体 三、系统测试1、系统注册/登录测试2、Resident-居民功能测试3、Samper-采样人员功能测试4、Checker-检测人员功能测试 总结 前言 学习了那么久的Java语法,总体感觉就是Java的语法知识更抽象,知识点也更琐碎。所以是时候来使用学过的知识做一个Java小项目了,一方面是对学过知识的总结,另一方面也可以通过项目来提示自己的编程能力。疫情发展到今天正在逐渐成为过去式,为纪念当年与疫情作斗争的日子,那么下面就以《核酸检测信息管理系统》为这次项目的主题。
一、功能与需求分析 核酸检测信息管理系统顾名思义就是对核酸检测中产生的各种信息进行管理,其中可能包括一些用户的个人信息,账户信息等,同时还应具有将数据进行分类管理能力,给使用者提供一些便捷的管理接口等,具体需求大致分为如下三个部分:
1、系统设计的初衷: 该系统的目的是为了更好地管理核酸检测信息,使得居民、采样人员和检测人员能够高效地使用系统。
2、系统的用户: 居民、采样人员和检测人员是该系统的三类用户,每类用户都有一些特定的功能。
(1)居民用户的功能:居民用户可以使用系统进行核酸预约登记、查询预约信息、修改预约信息、删除预约信息以及检测报告查询。
(2)采样人员用户功能: 采样人员用户可以使用系统查询已预约人员名单、采样信息录入和查询采样记录。
(3)检测人员用户功能: 检测人员在这个系统中可以查询已采样人员名单、检测结果录入和查询检测记录。
3、其他基本功能:
(1)该系统应分类管理不同用户的访问权限,以免发生访问冲突。
(2)该系统应具有数据存储的能力。需要支持用户数据的存储,以便对数据信息进行有效的检索和操作。
(3)该系统应具有最基本的登录验证功能,保护系统和用户信息的安全。
基于面向对象的设计思想,结合以上需求,我们可以画出如下具体业务流程图:
二、详细设计与实现 为了能够对系统内各部分信息,以及系统的各部分功能进行更好的分类管理,这里建了3个包和一个主函数:
1、data包 data包是系统的信息区,主要包含了用户核酸检测的个人信息、用户的账号和密码信息。这里面的信息也是之后operation包中各个功能类操作的信息来源,可以说是整个系统的基础核心。
(1)Data+DataBase Data类中是系统中核酸检测所需的各种信息,这里对这些信息采用了private封装,仅提供对外的set和get方法便于之后对这些信息的处理。同时增加了一些基本信息的构造方法,方便对用户基本信息的初始化。最后便于信息的显示,重写了Data类下的toString方法。
package data; public class Data { private String name;//姓名 private String id;//身份证号 private String phone;//手机号 private String type;//预约类型 private boolean isOrdered;//是否已预约 private boolean isSampled;//是否已采样 private boolean isChecked;//是否已检测 private boolean isNegative;//是否阴性 public Data(String name, String id, String phone, String type) { this.
1、搜索
#搜索 s = "school class student" print(s.find("sc")) #返回最小索引值 print(s.rfind("ool")) #返回最大索引值 # 替换 print(s.replace("school","university")) #对齐 print("26岁的年纪扬帆起航".center(30)) #居中对齐左右30空格 print("26岁的年纪扬帆起航".center(30,'*')) #居中对齐左右30个* print("26岁的年纪扬帆起航".ljust(30,'*')) #左对齐补30个* print("26岁的年纪扬帆起航".rjust(30,'*')) #右对齐补30个* # 统计 print("helloworld".count('o')) print("helloworld".count('l')) # 分离 print("helloworld".split('w')) print("127.0.0.1".split('.')) # 以什么进行连接 IP = "127.0.0.1" s = IP.split('.') print(s) v = '.'.join(s) k = '@'.join(s) print(v) print(k) # 反转 print(' '.join(input("输入:").split()[::-1])) 2、题目
# 给定一个字符串来代表一个学生的出勤纪录,这个纪录仅包含以下三个字符: # 'A' : Absent,缺勤 # 'L' : Late,迟到 # 'P' : Present,到场 # 如果一个学生的出勤纪录中不超过一个'A'(缺勤)并且不超过两个连续的'L'(迟到),那么这个学生会被奖赏。 # 你需要根据这个学生的出勤纪录判断他是否会被奖赏。 # 示例 1: # 输入: "
一、Vue组件表格文档 地址:
https://gitee.com/264727564/element-plus-table-ext
1. 功能介绍 一个基于element plus table 的表格封装组件,可以用来显示排序、过滤、导出、转图标、搜索、全屏等功能。
2. 使用 在Vue中使用Vue组件表格:
<vue-table :data="data" :columns="columns" :config-table="config" :config-event="{ 'row-click':rowClick }"> </vue-table> <script> import vueTable from './components/element-plus-table-ext.vue'; export default { data(){ return { config:{ height:"400px", border:true }, data:[], columns:[ {code:"name",name:"姓名",sortable:true,dataType:"column"}, {code:"address",name:"地区",sortable:true,dataType:"column"}, {code:"date",name:"日期",sortable:true,dataType:"column"}, {code:"money",name:"支付金额",sortable:true,dataType:"number"}, {code:"number",name:"购买数量",sortable:true,dataType:"number"}, {code:"price",name:"单价",sortable:true,dataType:"number"}, ], } }, created(){ var dataRand={ name:['张三','李四','王五','张飞','关羽','小明','小红','小白'], address:['北京','深圳','上海','广州','成都','黑龙江','乌鲁木齐','香港'], date:['2020-01','2020-02','2020-03','2020-04','2020-05','2020-06','2020-07','2020-08','2020-09','2020-10'] } for(var i=0;i<30;i++){ var row={ name:dataRand.name[this.rand(dataRand.name.length)], address:dataRand.address[this.rand(dataRand.address.length)], date:dataRand.date[this.rand(dataRand.date.length)], number:5+this.rand(100), price:5+this.rand(200) }; row.money=row.number*row.price; this.data.push(row); } }, methods:{ rowClick(e){ console.
最近公司有几个服务遇到了瓶颈,也就是数据量增加了,没有人发现,这不是缺少一个监控服务和告警的系统吗? 主要需求是监控每个服务,顺带监控一下服务器和一些中间件,这里采集的2种,zabbix和prometheus,由于我们要监控的是Docker容器中的服务,最终选择prometheus。
如下:
一 实现功能 服务宕机,不能提供服务,飞书收到告警信息。容器中服务占用分配内存达到50, 飞书收到预警信息。容器中服务中JVM堆内存占用达到80, 飞书收到预警信息。服务发生OOM后,服务可以立刻重启。 二:流程图 三 步骤 确定要监控的docker服务, 这里以公司的A服务为例子
查看服务的Dockerfile 和run.sh Dockerfile是构建docker镜像,run.sh是启动服务用的
1.1 Dockerfile中java执行命令添加:
"-XX:+HeapDumpOnOutOfMemoryError","-XX:HeapDumpPath=/temp/dump","-XX:+ExitOnOutOfMemoryError","-XX:MaxRAMPercentage=75.0"
-XX:+HeapDumpOnOutOfMemoryError:参数表示当JVM发生OOM时,自动生成DUMP文件
-XX:HeapDumpPath=/temp/dump:生成dump目录文件的位置
-XX:+ExitOnOutOfMemoryError:JVM在第一次出现内存不足错误时退出,启动JVM实例
-XX:MaxRAMPercentage=75.0: 这为JVM定义了75%的总内存限制
查看服务目前容器大小,和占用内存大小,保证占用内存稳定在30%一下。
docker stats dcda4228b794
这边找了一个47%的,只给了1G的容器大小。需求中超过50%就会告警。
如果超过50%,需要在启动容器的run.sh命令中提升初始容器大小
修改--memory 1024m \ --memory-swap 1024m \的值,是容器的内存大小
以上是容器要做的一些调整,也是自己定义的规则。
2. Idea中找到A应用,修改POM和 application.properties文件
application.properties中添加
management.endpoint.health.show-details=always
management.endpoints.web.exposure.include=*
这边要注意,如果你是yml文件 management.endpoints.web.exposure.include=*,
这个 * 一定要加 ''单引号,*在yml文件中是通配符。
POM中添加,目的是当前服务可以提供一些监控指标
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> 注意,如果你的服务属于对外接口访问服务,有Shiro拦截的话要配置
filterChainDefinitionMap.put("/actuator/prometheus", "anon"); 至此完成代码的整改,可以提交代码,部署服务。
确定服务正常启动:输入docker ps -a (不加-a就看正常运行的服务,-a是看所有的服务,包括停止的)
去服务器厂商放开当前服务对外的端口号,主要是对指定监控的服务器放开,不是所有
环境地址访问 http://ip:port/actuator/prometheus
1、Opc 基金会git地址:OPC Foundation · GitHub
其中:UA-.NETStandard 、UA-.NETStandard-Samples比价有参考价值
2、参数传递方式:ns=2;s=参数名(ns表示命名空间索引,一般为2)
特殊情况可以查看所有命名空间:ns=0;i=2255,也可以用(OpcUaHelper.Tool)工具查看
下载地址:C#opc学习资源代码-其它文档类资源-CSDN下载
3、根据opc基金会提供方法整理出调用代码:OPCUAC#控制类库-制造文档类资源-CSDN下载
using Opc.Ua; using Opc.Ua.Client; using Opc.Ua.Configuration; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; namespace OPCUALink { /// <summary> /// OPC UA Client with examples of basic functionality. /// </summary> public class UAClient { #region Constructors public UAClient(bool isdebug = false) { if (isdebug) { return; } ApplicationInstance application = new ApplicationInstance(); application.ApplicationName = SessionName; application.
一个大文件夹中包含许多子文件夹,子文件夹中又包含不同类型的图片,目标:将子文件夹中的图片移动到一个文件夹中,python代码如下:
import os import shutil source_folder = '/path/to/source/folder' destination_folder = '/path/to/destination/folder' # 自动创建输出目录 if not os.path.exists(destination_folder): os.makedirs(destination_folder) # 遍历所有子文件夹 for parent_folder, _, file_names in os.walk(source_folder): # 遍历当前子文件夹中的所有文件 for file_name in file_names: # 只处理图片文件 if file_name.endswith(('jpg', 'jpeg', 'png', 'gif')): # 构造源文件路径和目标文件路径 source_path = os.path.join(parent_folder, file_name) destination_path = os.path.join(destination_folder, file_name) # 复制文件到目标文件夹 shutil.copy(source_path, destination_path)
前言
前段时间在做一个Flutter相关的App开发的时候,iPhone手机在连接Mac电脑,然后运行VS Code启动Flutter程序,然后可以正常安装到手机上,但是安装之后更新了手机的系统,而且手机系统更新到最新的iOS 14.4,然后重新打开手机里面安装的Flutter程序,然后遇到了程序启动问题,那么本文就来分析一下具体原因和解决方法。
报错提示
手机系统更新到iOS 14.4以后,运行手机安装的Flutter程序,然后程序运行不起来,并提示如下信息:
In iOS 14+,debug mode Flutter apps can only be launched from Flutter tooling, IDEs with Flutter plugins orfrom Xcode. Alternatively,build in profile or release modes to enable launching from the home screen. 分析
首先来分析一下上述报错的英文,直接翻译一下,翻译之后的意思如下所示:
在iOS 14+中,调试模式的Flutter应用程序只能从Flutter工具里面启动运行,IDEs(包括VS Code、Android Studio)有Flutter插件或Xcode启动。 或者,构建的时候使用配置文件或使用release模式,以支持能够从主屏幕启动。 报错原因
在debug模式下,Flutter的热重载是把默认编译方式改为JIT,但是在iOS 14系统以后,苹果系统对JIT的编译模式进行了限制,造成在debug模式下基于Flutter的App运行不起来。
分析之后
通过分析上述提示的文字之后,得到了两种解决方法来处理上述报错问题。
注意事项
通过XCode直接打开Flutter应用程序,直接打开XCode的设置选项,把编译模式修改为release模式,然后重新连接手机,运行程序,运行成功之后,断开连接,重新在手机里打开程序,可以正常运行。
但是如果用Xcode12版本运行项目连接手机进行Flutter应用安装,然后手机断开与电脑连接,再次打开手机安装的应用程序,一定会闪退,所以该方式不行。
解决步骤
解决上述错误提示有两种方式:方法一是直接使用Flutter的release模式,方法二是直接使用profile。
方法一:
通过直接使用Flutter的release模式来解决上述错误,直接在项目启动的终端里面输入命令行:
flutter run --release 回车,然后即可运行Flutter的release模式,然后断开手机与电脑的连接,再次打开手机里面安装的这个Flutter应用,不再闪退。
方法二:
找到电脑上面安装的Flutter文件位置,直接找到flutter/packages/flutter_tools/bin/xcode_backend.sh文件,直接把Flutter的编译模式设置为release模式,手机重新连接电脑运行程序,然后断开电脑连接,再次打开手机上安装的app应用,即可正常打开运行程序不闪退。
建议使用方法一来解决上述问题,使用命令行flutter run --release的方式来操作,很方便。
C++学习笔记(1)
学习是一件任重而道远的事情,与其焦虑不如动手起来,借助平台记录自己学习笔记,希望和大家多多交流,今天又是努力成为程序媛的一天!
01.书写第一个C++程序(“hello world”) 代码运行环境:VScode 2022 C++ 桌面版
#include<iostream> using namespace std; int main() { cout << "hello world" << endl; system("pause"); return 0; } 运行结果 语句结构:cout << "这里输入你想输出的内容” << endl;
易错小tips: endl 这里最后是字母l,而不是数字1;语句结束时记得加分号; 02.添加注释 在代码中添加注释对程序员来说至关重要,它能帮助我们后面再来看该程序以及方便小组其他成员查看理解你的代码,完成项目合作。
前期学习一定要养成写代码加注释的习惯,方便后期查看理解代码。
// 这是单行注释 /* 这是多行注释 main函数是一个程序的入口 有且只有一个 03.变量 每个值都有一个内存地址来存放,使用变量就可以给这个内存空间起名,方便使用。
变量的语法结构:数据类型 变量名 = 变量初始值
在程序中创建一个变量如下:
#include<iostream> using namespace std; int main() { int a = 10;//创建一个变量a并赋值 cout << a << endl;//输出a的值 system("pause"); return 0; } 运行结果:
简介: 有的时候我们会遇到将word转换为pdf的需求,当然,不仅仅是word转换为PDF,像图片转换为pdf等等这样的转换工作。
如果涉及到以上这些需求,那么使用LibreOffice不失为一个好的方式,从转换后的准确率、转换速度、转换格式的支持LibreOffice都是比较给力的。下面,让我们具体学习下如何安装和使用libreOffice
官网信息: https://zh-cn.libreoffice.org/download/libreoffice/
安装 建议选择稳定版本,这里我选择了 LibreOffice 7.4.5。
下载和解压需要的包 选择你对应操作系统的包,我这里是Linux的rpm包 https://downloadarchive.documentfoundation.org/libreoffice/old/7.4.5.1/rpm/x86_64/
一般在最下面:
将上述的包下载下来后上传到服务器上,解压并安装 tar -zxvf LibreOffice_7.4.5.1_Linux_x86-64_rpm_langpack_zh-CN.tar.gz tar -zxvf LibreOffice_7.4.5.1_Linux_x86-64_rpm.tar.gz cd /LibreOffice_7.4.5.1_Linux_x86-64_rpm/RPMS/ yum localinstall *.rpm cd /LibreOffice_7.4.5.1_Linux_x86-64_rpm_langpack_zh-CN/RPMS/ yum localinstall *.rpm 安装成功后,会在 /opt/目录下生成一个libreoffice7.4的目录 配置环境变量 vim /etc/profile。 在文档底部添加如下内容。 然后source /etc/profile 使得配置生效
# libreoffice export LibreOffice_PATH=/opt/libreoffice7.4/program export PATH=$LibreOffice_PATH:$PATH 正常服务器不缺少底层依赖的话,这个时候你已经成功了,可以尝试下输入 libreoffice7.4 --help。 出现以下内容说明已经可以了。可以直接试下转换。否则看下个标题。
报错 No such file or directory 很明显,缺少依赖了。安装一下。
yum install cairo -y yum install cups-libs -y yum install libSM -y 试着转换pdf 经过前面的步骤我们已经安装好了LibreOffice,现在试着转换个word为pdf吧。 上传个word到服务器上。然后输入以下命令:
1、判断大小写数字、字母、标题
a = "123" b = "abc" c = "123abc" d = "%_*" e = "HelLo" #判断是不是数字 print(a.isdigit()) #判断是不是字母 print(b.isalpha()) #判断是不是数字字母组合 print(c.isalnum()) print(a.isalnum()) #全部变成大写 print(e.upper()) print(e.isupper()) #全部变成小写 print(e.lower()) print(a.islower()) print(b.islower()) print(a.istitle()) 2、startswith、endswith判断
file = "fc.log" if file.startswith('.log'): print("这是以log结尾的日志文件") else: print("这不是以log结尾的日志文件") if file.endswith('.log'): print("这是以log结尾的日志文件") else: print("这不是以log结尾的日志文件") url1 = "http://127.0.0.1/Download" if url1.startswith('http://'): print("这是以http开头的网页信息") else: print("这不是以http开头的网页信息") 3、命名规则训练
""" 由字母、数字、下划线组成 只能以字母或者下划线开头 尽量不要和关键字重名 s = 'sumscope#'是错误的命名,因为含有特殊字符 """ while True: keywords = ["exit","break","continue","import"] num = input("
也不知道是什么原因,输入nvidia-smi会有这个bug。看到一个帖子中遇到和我类似的问题:
I have several issues actually, but I am not sure whether they are related.
nvidia-smi out puts no device were found. The system cannot detect the second display. The fractional scaling is not working (can only set to 200% even if I set 150%). The update rate is incorrect in system setting. 有一个评论解决了我的问题:
Wrong driver, please either switch to the non “-open” driver version in Software&Updates or set the appropriate module option.
一、Docker Compose 1、前言
我们知道使⽤⼀个 Dockerfile 模板⽂件,可以让⽤户很⽅便的定义⼀个单独的应⽤容器。然⽽,在⽇常⼯作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。 例如要实现⼀个 Web 项⽬,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚⾄还包括负载均衡容器等,我们只能一个一个`写dockerfile文件,然后bulid构建,run手动操作单个容器` Compose 恰好满⾜了这样的需求。它允许⽤户通过⼀个单独的 docker-compose.yml 模板⽂件(YAML 格式) 来定义⼀组相关联的应⽤容器为⼀个项⽬(project). 微服务。 100个微服务!依赖关系。 # Compose 项⽬是 Docker 官⽅的开源项⽬,负责实现对 Docker 容器集群的快速编排。 2、官方介绍
Docker Compose来轻松高效的管理容器,定义运行多个容器。
1、Compose 中有两个重要的概念
# 1、服务 ( service ): ⼀个应⽤的容器,实际上可以包括若⼲运⾏相同镜像的容器实例(web、redis、mysql ...)。 # 2、项⽬ ( project ): 由⼀组关联的应⽤容器组成的⼀个完整业务单元,在 docker-compose.yml ⽂件中定义(博客、web、mysql)。 # 启动docker-compose up 可以启动多个服务 2、三步骤
1、Dockerfile 保证我们的项目可以在任何地方运行。 2、定义组成您的应用程序的服务,docker-compose.yml 以便它们可以在隔离的环境中一起运行。 # services 什么是服务 # docker-compose.ym 这个文件如何写 3、运行docker compose up和码头工人组成命令启动并运行你的整个应用程序。 也可以docker-compose up使用 docker-compose 二进制文件运行。 # 启动项目 3、Compose是Docker官方的开源项目,需要安装!
前言 早在2022年我们就建了第一个BAT等大厂的面试群给大家讨论面试的东西。期间累计有2158个群友分享了自己的Android面试真经,这是我们持续更新整理的2023年最新的阿里、百度、腾讯、字节跳动等大厂的Android面试真题解析!
这其中就有很多成员已经斩获今日头条、抖音、阿里P7等岗位的offer。当然也有很多成员面试虽然失败了,但也分享了很多失败的经验教训。在这里一并对他们表示感谢!正是因为大家的奉献和支持,让我们的这份面试真题解析已经累计下载超10万次!
面试题如下(答案太长不方便展开,仅仅展示部分)
Android属性动画实现原理;补间动画实现原理 Android各个版本API的区别Requestlayout,onlayout,onDraw,DrawChild区别与联系invalidate和postInvalidate的区别及使用 Activity-Window-View 三者的差别谈谈对Volley的理解 描述一次网络请求的流程 HttpUrlConnection 和 okhttp关系 面试经验总结 1.一定要谨慎对待写在简历上的东西,一定要对简历上的东西非常熟悉。因为一般情况下,面试官都是会根据你 的简历来问的;
2.能有一个上得了台面的项目也非常重要,这很可能是面试官会大量发问的地方,所以在面试 之前好好回顾一下自己所做的项目;
3.和面试官聊基础知识比如设计模式的使用、多线程的使用等等,可以结合具体的项目场景或者是自己在平时是 如何使用的;
4.建议提前了解一下自己想要面试的公司的价值观,判断一下自己究竟是否适合这个公司。
5.另外,我个人觉得面试也像是一场全新的征程,失败和胜利都是平常之事。所以,劝各位不要因为面试失败而灰心、 丧失斗志。也不要因为面试通过而沾沾自喜,等待你的将是更美好的未来,继续加油!
面试复习笔记: 这份资料从2022年春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。 节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。 给文章留个小赞,就可以免费领取啦~
第一章 Java 方面 (一)Java 基础部分
抽象类与接口的区别?
分别讲讲 final,static,synchronized 关键字可以修饰什么,以及修饰后的作用?
请简述一下String、StringBuffer和StringBuilder的区别?
“equals”与“==”、“hashCode”的区别和使用场景?
Java 中深拷贝与浅拷贝的区别?
谈谈Error和Exception的区别?
什么是反射机制?反射机制的应用场景有哪些?
谈谈如何重写equals()方法?为什么还要重写hashCode()?
Java 中 IO 流分为几种?BIO,NIO,AIO 有什么区别?
谈谈你对Java泛型中类型擦除的理解,并说说其局限性?
String为什么要设计成不可变的?
说说你对Java注解的理解?
谈一谈Java成员变量,局部变量和静态变量的创建和回收时机?
请说说Java中String.length()的运作原理?
(二)Java 集合
谈谈List,Set,Map的区别?
谈谈ArrayList和LinkedList的区别?
请说一下HashMap与HashTable的区别
谈一谈ArrayList的扩容机制?
HashMap 的实现原理?
请简述 LinkedHashMap 的工作原理和使用方式?
谈谈对于ConcurrentHashMap的理解?
(三)Java 多线程
Java 中使用多线程的方式有哪些?
一.需求背景 跟大学室友闲谈时,了解到他公司正在做项目内对数据库敏感字段实现自动加解密的需求,使用的技术是Springboot,Mybatis-Plus,MySql等技术栈,加密算法是用的AES,密钥是放在华为云,这里实现一个阉割版的demo,仅供有兴趣的同学进行参考。
二.前置条件 首先我自己在日常搭了一个普通的springboot项目,目前还没有前台,所以就在浏览器请求tomcat模拟接口。
其次,这里的是实现主要是应用了Mybatis的拦截器,AES算法,mysql等技术栈,需要了解一下相关背景。
1.AES算法 AES的全称是Advanced Encryption Standard,意思是高级加密标准。它的出现主要是为了取代DES加密算法的,因为我们都知道DES算法的密钥长度是56Bit,因此算法的理论安全强度是2的56次方。但二十世纪中后期正是计算机飞速发展的阶段,元器件制造工艺的进步使得计算机的处理能力越来越强,虽然出现了3DES的加密方法,但由于它的加密时间是DES算法的3倍多,64Bit的分组大小相对较小,所以还是不能满足人们对安全性的要求。于是1997年1月2号,美国国家标准技术研究所宣布希望征集高级加密标准,用以取代DES。AES也得到了全世界很多密码工作者的响应,先后有很多人提交了自己设计的算法。最终有5个候选算法进入最后一轮:Rijndael,Serpent,Twofish,RC6和MARS。最终经过安全性分析、软硬件性能评估等严格的步骤,Rijndael算法获胜。
在密码标准征集中,所有AES候选提交方案都必须满足以下标准:
分组大小为128位的分组密码。
必须支持三种密码标准:128位、192位和256位。
比提交的其他算法更安全。
在软件和硬件实现上都很高效。
2.Mybatis拦截器 拦截器(Interceptor)在 Mybatis 中被当做插件(plugin)对待,官方文档提供了 Executor(拦截执行器的方法),ParameterHandler(拦截参数的处理),ResultSetHandler(拦截结果集的处理),StatementHandler(拦截Sql语法构建的处理) 共4种,并且提示“这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码”。
拦截器的使用场景主要是更新数据库的通用字段,分库分表,加解密等的处理。
1.1 MyBatis自定义拦截器 实现org.apache.ibatis.plugin.Interceptor接口。添加拦截器注解org.apache.ibatis.plugin.Intercepts配置文件中添加拦截器 1.2 在MyBatis中可被拦截的类型有四种(按照拦截顺序) Executor:拦截执行器的方法。ParameterHandler:拦截参数的处理。ResultHandler:拦截结果集的处理。StatementHandler:拦截Sql语法构建的处理,绝大部分我们是在这里设置我们的拦截器 先执行每个插件的plugin方法,若是@Intercepts注解标明需要拦截该对象,那么生成类型对象的代理对象。(即使该插件需要拦截该类型对象,但是依旧会执行下一个插件的plugin方法)。知道执行完毕所有的plugin方法。在执行每个Intercept方法。
1.3 拦截器注解的作用: 自定义拦截器必须使用MyBatis提供的注解来声明我们要拦截的类型对象。
Mybatis插件都要有Intercepts注解来指定要拦截哪个对象哪个方法。我们知道,Plugin.wrap方法会返回四大接口对象的代理对象,会拦截所有的方法。在代理对象执行对应方法的时候,会调用InvocationHandler处理器的invoke方法。
1.4 拦截器注解的规则: 具体规则如下:
@Intercepts({ @Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}), @Signature(type = StatementHandler.class, method = "update", args = {Statement.class}), @Signature(type = StatementHandler.class, method = "batch", args = {Statement.class}) }) 复制代码 @Intercepts:标识该类是一个拦截器@Signature:指明自定义拦截器需要拦截哪一个类型,哪一个方法; type:对应四种类型中的一种;method:对应接口中的哪类方法(因为可能存在重载方法);args:对应哪一个方法; 1.
element 的 el-input-number的默认值设置为空
用 el-input-number 来限制输入框智能输入数字,例如价格之类的,v-model 设为 空 和 null 时,默认的值显示为允许输入的最小值。如下:
<el-input-number v-model="formData.idx" :precision="0" :step="1" :min="1" :max="100000"></el-input-number> <el-input-number v-model="formData.winnersNum" :precision="0" :step="1" :min="1" :max="500"></el-input-number> data(){ return { formData: { idx: null, winnersNum: '' } } } 页面效果:
解决方法:v-model 设置为 undefined ,就可以了。
data(){ return { formData: { idx: undefined, winnersNum: undefined } } } 页面效果:
1、Hologres 0.8 创建数组类型外部表采坑
ODPS:CREATE TABLE `test_clue` ( `id_c` array<bigint>, `name` array<string> ) ;
Holo:
CREATE FOREIGN TABLE test_clue(
id int8[],
name text[])
SERVER odps_server
OPTIONS(project_name 'itsl_dev', table_name 'test_clue');
报错:
原因:odps文件类型不是orc
odps的文件类型有哪些:??aliorc
hive的文件存储类型:
||SequenceFile
Hadoop用来存储二进制形式的[Key,Value]对而设计的一种平面文件(Flat File)。
||TextFile文本格式
||RCFile一种列存储格式
||ORC ★一种列存储格式 进阶版RCFile
||Parquet ★一种列存储格式AVRO
||JsonFile(json文件)
||InputFormat
解决办法:
odps建表前加:
set odps.sql.default.file.format=aliorc;
set odps.storage.force.aliorc=true;
CREATE TABLE `test_clue` ( `id_c` array<bigint>, `name` array<string> ) ;
2、Hologres 0.8 使用get_json_object函数
先用super账号设置开启hive函数支持:CREATE extension hive_compatible;
SELECT
get_json_object(message,'$.profileData.advertisingID') AS advertisingID
在 Visual Studio 2019 中配置 pthread 库的多线程支持,可以按照以下步骤进行:
下载 pthread 库。可以从 https://sourceforge.net/projects/pthreads4w/files/pthreads-w32/ 下载最新版本的 pthread 库。
百度网盘获取:链接:https://pan.baidu.com/s/13ZSPfFEQyd73TZNivaeUIA?pwd=li3y 提取码:li3y将下载好的 pthread库解压到一个路径下,例如 C:\pthread。在 Visual Studio 2019 中创建一个新的控制台应用程序项目。点击“项目”菜单,选择“属性”。在属性页中,选择“VC++目录”选项卡,在“包含目录”中添加 pthread.h 的所在目录,例如 C:\pthread\Pre-built.2\include。在“库目录”中添加 pthread 库的 lib 文件所在目录,例如 C:\pthread\Pre-built.2\lib\x64和C:\pthread\Pre-built.2\lib\x86。在“链接器”选项卡中,选择“输入”选项卡,在“附加依赖项”中加入 pthreadVC2.lib 和 pthreadVCE2.lib。在代码中添加头文件 #include <pthread.h>。 编写多线程代码,例如:
#include <iostream> #include <pthread.h> using namespace std; void* func(void* arg) { cout << "Hello from thread!" << endl; pthread_exit(NULL); } int main() { pthread_t thread; int rc = pthread_create(&thread, NULL, func, NULL); if (rc) { cout << "
知识点预览 (拜托拜托!一定要去看文末的总结,是我每次刷完题后的反思回顾)
Java怎么返回数组 ------ 具体见0001 两数之和 暴力法下面的补充
用哈希表降低双重遍历的时间复杂度(代价是空间复杂度的增加)------- 具体见0001 两数之和 哈希表法的思路和算法二
用快慢指针遍历比较数组元素及修改数组元素 ------- 具体见0026 删除有序数组中的重复项的思路和算法三 , 0027 移除元素的思路和算法四 二分法查找目标数组元素 ------- 具体见0035 搜索插入位置的思路和算法五 , 0034 在排序数组中查找元素的第一个和最后一个位置的思路和算法六
1、0001 两数之和 题目描述 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那两个整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9输出:[0,1]解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。示例 2:
输入:nums = [3,2,4], target = 6输出:[1,2]示例 3:
输入:nums = [3,3], target = 6输出:[0,1]
提示: