链接:https://pan.baidu.com/s/1aMjVfq1yEgJ-o3ra-F_V9g 提取码:zzc1
引言 Yolo(You Only Look Once)是一种one-stage目标检测算法,即仅需要 “看” 一次就可以识别出图片中物体的class类别和边界框。Yolov8是Ultralytics公司最新推出的Yolo系列目标检测算法,可以用于图像分类、物体检测和实例分割等任务。
根据官方描述,Yolov8是一个SOTA模型,它建立在Yolo系列历史版本的基础上,并引入了新的功能和改进点,以进一步提升性能和灵活性,使其成为实现目标检测、图像分割、姿态估计等任务的最佳选择。其具体创新点包括一个新的骨干网络、一个新的Ancher-Free检测头和一个新的损失函数,可在CPU到GPU的多种硬件平台上运行。
此外,Yolov8还有一个特点就是可扩展性,ultralytics没有直接将开源库命名为Yolov8,而是直接使用"ultralytics",将其定位为算法框架,而非某一个特定算法。这也使得Yolov8开源库不仅仅能够用于Yolo系列模型,而且能够支持非Yolo模型以及分类分割姿态估计等各类任务。
总而言之,Yolov8是Yolo系列模型的最新王者,各种指标全面超越现有对象检测与实例分割模型,借鉴了Yolov5、Yolov6、YoloX等模型的设计优点,在全面提升改进Yolov5模型结构的基础上实现,同时保持了Yolov5工程化简洁易用的优势。
如下表所示是基于COCO Val 2017数据集测试并对比Yolov8和Yolov5的mAP、参数量和FLOPs结果。由此可以看出,Yolov8相比Yolov5精度提升比较多,但是n/s/m模型参数量和flops增加不少,但是相比Yolov5大部分模型推理速度变慢了。
FlOPs(floating point operations):浮点运算次数,用于衡量算法/模型的复杂度。
FLOPS(全部大写)(floating point operations per second):每秒运算的浮点数,可以理解为计算速度,用于衡量硬件性能。
这里是衡量模型的复杂度,因此选择FlOPs。
模型Yolov5(300epoch)params(M)FLOPS@640(B)Yolov8(500epoch)params(M)FLOPS@640(B)n28.01.94.537.33.28.7s37.47.216.544.911.228.6m45.421.249.050.225.978.9l49.046.5109.152.943.7165.2x50.786.7205.753.968.2257.8 这里需要注意的是,目前各个Yolo系列算法都只是在COCO数据集上性能提升明显,然而在自定义数据集上的泛化性尚未得到充分验证。
Yolov8创新点 Yolov8主要借鉴了Yolov5、Yolov6、YoloX等模型的设计优点,其本身创新点不多,偏重在工程实践上,具体创新如下:
提供了一个全新的SOTA模型(包括P5 640和P6 1280分辨率的目标检测网络和基于YOLACT的实例分割模型)。并且,基于缩放系数提供了N/S/M/L/X不同尺度的模型,以满足不同部署平台和应用场景的需求。Backbone:同样借鉴了CSP模块思想,不过将Yolov5中的C3模块替换成了C2f模块,实现了进一步轻量化,同时沿用Yolov5中的SPPF模块,并对不同尺度的模型进行精心微调,不再是无脑式一套参数用于所有模型,大幅提升了模型性能。Neck:继续使用PAN的思想,但是通过对比YOLOv5与YOLOv8的结构图可以看到,YOLOv8移除了1*1降采样层。Head部分相比YOLOv5改动较大,Yolov8换成了目前主流的解耦头结构(Decoupled-Head),将分类和检测头分离,同时也从Anchor-Based换成了Anchor-Free。Loss计算:使用VFL Loss作为分类损失(实际训练中使用BCE Loss);使用DFL Loss+CIOU Loss作为回归损失。标签分配:Yolov8抛弃了以往的IoU分配或者单边比例的分配方式,而是采用Task-Aligned Assigner正负样本分配策略。 Yolov8网络结构 Yolov8模型网络结构图如下图所示。
Backbone Yolov8的Backbone同样借鉴了CSPDarkNet结构网络结构,与Yolov5最大区别是,Yolov8使用C2f模块代替C3模块。具体改进如下:
第一个卷积层的Kernel size从6×6改为3x3。所有的C3模块改为C2f模块,如下图所示,多了更多的跳层连接和额外Split操作。Block数由C3模块3-6-9-3改为C2f模块的3-6-6-3。 C2f与C3对比
由上图可以看出,C2f中每个BottleNeck的输入Tensor的通道数channel都只是上一级的0.5倍,因此计算量明显降低。从另一方面讲,梯度流的增加,也能够明显提升收敛速度和收敛效果。
C2f模块首先以输入tensor(n,c,h,w)经过Conv1层进行split拆分,分成两部分(n,0.5c,h,w),一部分直接经过n个Bottlenck,另一部分经过每一操作层后都会以(n,0.5c,h,w)的尺寸进行Shortcut,最后通过Conv2层卷积输出。也就是对应n+2的Shortcut(第一层Conv1的分支tensor和split后的tensor为2+n个bottenlenneck)。
Neck YOLOv8的Neck采用了PANet结构,如下图所示。
Backbone最后SPPF模块(Layer9)之后H、W经过32倍下采样,对应地Layer4经过8倍下采样,Layer6经过16倍下采样。输入图片分辨率为640*640,得到Layer4、Layer6、Layer9的分辨率分别为80*80、40*40和20*20。
Layer4、Layer6、Layer9作为PANet结构的输入,经过上采样,通道融合,最终将PANet的三个输出分支送入到Detect head中进行Loss的计算或结果解算。
与FPN(单向,自上而下)不同的是,PANet是一个双向通路网络,引入了自下向上的路径,使得底层信息更容易传递到顶层。
Head Head部分相比Yolov5改动较大,直接将耦合头改为类似Yolox的解耦头结构(Decoupled-Head),将回归分支和预测分支分离,并针对回归分支使用了Distribution Focal Loss策略中提出的积分形式表示法。之前的目标检测网络将回归坐标作为一个确定性单值进行预测,DFL将坐标转变成一个分布。
yaml配置文件解析 参数部分 Yolov8采用Anchor-Free方式,因而在yaml文件中移除了anchors参数,并且将多个不同版本的模型参数写在一个yaml,同时在深度因子和宽度因子后面增加了 最大通道数 这一参数。
Backbone # [from, repeats, module, args] from:本层的来源,即就是输入。-1表示将上层的输出作为本层的输入。 repeats:本层重复次数。 module:本层名称。 args:本层参数。 第0层:[-1,1,Conv,[64, 3, 2]] #0-P1/2 -1表示将上层的输出作为本层的输入,第0层的输入是640*640*3的图像。Conv表示卷积层。[64, 3, 2]:输出通道数64,卷积核大小k为3,stride步长为2。由此计算padding为1。输出特征图大小(向下取整1):f_out=((f_in - k + 2*p ) / s )=((640 - 3 + 2*1 ) / 2 )=320。所以本层输出特征图尺寸为320*320*64,长宽为原输入图片的1/2。 第1层:[-1,1,Conv,[128, 3, 2]] # 1-P2/4 [128, 3, 2]:输出通道数128,卷积核大小k为3,stride步长为2。输出特征图大小(向下取整1):f_out=((f_in - k + 2*p ) / s )=((320 - 3 + 2*1 ) / 2 )=160。所以本层输出特征图尺寸为160*160*128,长宽为原输入图片的1/4。 第2层:[-1,3,C2f,[128, True]] [128, True]:128表示输出通道数,True表示Bottleneck有shortcut。本层输出特征图尺寸仍为160*160*128。 第3层:[-1,1,Conv,[256,3,2]] # 3-P3/8 [256,3,2]:输出通道数256,卷积核大小k为3,stride步长为2。输出特征图大小(向下取整1):f_out=((f_in - k + 2*p ) / s )=((160-3+ 2*1 )/2)=80。所以本层输出特征图尺寸为80*80*256,长宽为原输入图片的1/8。 …第9层:[-1,1,SPPF,[1024, 5]] [1024, 5]:1024表示输出通道数,5表示池化核大小k。输出特征图尺寸为20*20*1024。 Head 第10层:[-1,1,nn.
文章目录 1 前言2 抓包3 过程分析4 总结 1 前言 之前总是看到各种关于https流程的总结,关于数字证书和数字签名什么的也都知道个大概,但是具体https是怎么执行的一直也没验证过。看过一个视频讲得很好【HTTPS是什么?加密原理和证书。SSL/TLS握手过程】,今天想学着用WireShark抓包实验一下。
Wireshark官网https://www.wireshark.org/
2 抓包 (建议只留一个浏览器和Wireshark,不然包不好找)
首先打开Wireshark,双击自己正在使用的网络,比如下图中要双击WiFi: en0
之后就开始进行抓包了,可以看到有很多的TCP报文。在上面的filter框中输入tls就能够过滤出TLS的报文了。(建议选中顶部右数第五个图标让数据列表始终处于最下面的部分)这时,用浏览器打开一个https协议访问的网址,比如百度,观察Wireshark中新抓到的TLS报文:
可以看到Client Hello的报文,这也是https协议数据传输前浏览器和服务器握手的开始。记录下百度的IP地址,可以修改一下上面filter框的过滤条件为tls && (ip.dst == 103.235.46.250 || ip.src == 103.235.46.250),这样就能够过滤出与百度握手的包。
之后就可以从Client Hello到Encrypted Handshake Message查看https中tls握手的具体全过程了。 3 过程分析 根据上图中的过程查看报文内容对https握手的流程进行分析。
(在Server Hello Done之前的部分都是明文传输)
Client Hello
主要看安全传输层协议(TLS)。
可以看到,这一步中浏览器向服务器发送了:
1) TLS支持版本1.2(上面的1.0是TLS格式,对于不同TLS版本的显示可以参考这篇文章Wireshark抓包TLS协议栏显示版本不一致问题)
2) 第一随机数Random(随机数的作用在下面的第四步)
3) 支持的加密套件Cipher Suites(点开后可以看到所有的支持加密算法)。Server Hello
服务器收到Client Hello后,会回复一个Server Hello,报文的内容如下:
在这一步,服务器向浏览器回复了:
1) 确认TLS版本1.2
2) 第二随机数Random(随机数的作用在下面的第四步)
3) 确认加密套件Cipher SuiteCertificate, Server Key Exchange, Server Hello Done
Server Hello发送后,服务器还会接着发送证书和公钥给浏览器,报文内容如下:
在这一步中,服务器向浏览器发送了:
1) 服务器数字证书Certificates
PopUp弹窗组件
import React from "react" import { Modal, StyleSheet, TouchableOpacity, View } from 'react-native' export default (props) => { const { visible, onClose, children } = props return ( <Modal transparent visible={visible} animationType={'fade'} onRequestClose={() => onClose()}> <TouchableOpacity style={styles.overlay} activeOpacity={1} onPress={() => onClose()} /> <View style={styles.content}> {children} </View> </Modal> ) } const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)', }, content: { position: "absolute", left: 0, bottom: 0, width: "
小猫爪:嵌入式小知识17-XCP on CAN简介 0 目录1 前言2 XCP on CAN3 实战演练3.1 CONNECT3.2 GET_COMM_MODE_INFO和GET_STATUS3.3 GET_SEED和UNLOCK3.4 获取Slave信息3.5 SET_MTA和BUILD_CHECKSUM3.6 设置DAQ3.7 DAQ传输3.8 SHORT_UPLOAD3.9 标定3.10 FLASH Program END 0 目录 小猫爪:嵌入式小知识15-XCP基础简介小猫爪:嵌入式小知识16-XCP协议简介小猫爪:嵌入式小知识17-XCP on CAN简介小猫爪:嵌入式小知识18-XCP SeedNKey.dll
1 前言 前面已经对XCP协议做了非常细致的介绍,接下来就来看看XCP是怎样在CAN总线上进行工作的吧。参考资料:XCP协议规范2003。
2 XCP on CAN XCP在CAN上的实现也是非常的简单,首先得分配两个CAN ID,对于Master这一方来说,一个作为发,即CMD和STIM,一个作为收,即RES/ERR/EV/SERV和DAQ。这里需要注意的是STIM和DAQ可以有自己独立的CAN ID,但是需要使用SET_DAQ_ID命令CMD进行配置。
之前文章里已经提到过,在CAN上的XCP是不支持交互通信模式的,一般都是采用标准通信模式和块传输模式两者配合。
XCP在CAN上的协议包的体现为:
首先XCP Header为空,至于XCP Packet则与XCO协议一模一样。而XCP Tail则根据经典CAN的MAX_DLC(经典CAN的MAX_DLC固定为8)和XCP Packet长度LEN有以下两种情况:
MAX_DLC = LEN
这个时候XCP Packet把CAN帧的8个字节全部填满,XCP Tail为空。MAX_DLC > LEN
这个时候XCP Packet没有把CAN帧的8个字节填满,那么就需要填充到8个字节,这个时候XCP Tail即为填充。 对于CAN-FD,MAX_DLC只有以下值有效:8、12、16、20、24、32、48和64。这个时候有的朋友就要问了,那如果LEN > MAX_DLC的时候怎么办,不可能,这种事情在XCP on CAN上是不可能发生的,你放心吧。
3 实战演练 接下来来看看XCP的一些常用操作在CAN上的体现。当我将CANape配置完之后,点击Start,Master和Slave会进行怎样的交互呢?
具体流程如下:
3.1 CONNECT 首先使用CONNECT命令与Slave建立XCP连接。CONNECT的正响应具体描述如下:
根据上表就可以解析出Flash programming available,stimulation available,DAQ lists available, calibration/paging available,Intel format,AG为BYTE,不支持Slave Block Mode,支持命令GET_COMM_MODE_INFO命令获取通信配置,MAX_CTO = 8,MAX_DTO = 8, 还有协议层和传输层的版本号。
小猫爪:嵌入式小知识16-XCP协议简介 0 目录1 前言2 XCP协议简介2.1 各种包2.1 CMD2.2 RES2.3 ERR2.4 EV2.5 SERV2.6 DAQ2.7 STIM2.8 总结 2.2 错误处理2.2.1 Time-out Error Handling2.2.2 Error Code Error Handling 2.3 State machine END 0 目录 小猫爪:嵌入式小知识15-XCP基础简介小猫爪:嵌入式小知识16-XCP协议简介小猫爪:嵌入式小知识17-XCP on CAN简介小猫爪:嵌入式小知识18-XCP SeedNKey.dll 1 前言 上一节介绍了一下XCP的相关基础,为我们后续学习打下了坚实的基础,接下来就开始进行枯燥乏味的协议介绍。参考资料:XCP协议规范2003。
2 XCP协议简介 2.1 各种包 在XCP基础简介文章中,提到了XCP协议包分为CTO和DTO,然后又细分为CMD, RES, ERR, EV, SERV, DAQ, STIM,在上篇文章中已经对XCP协议包的格式进行了简单说明,XCP依靠PID来进行区分协议包类型,具体PID划分如下:
接下来来看看每一种包的形式和作用。
注:下面的表中出现的MAX_CTO和MAX_DTO,分别表示CTO包和DTO包的最大数据字节长度。
2.1 CMD CMD就是XCP的各种命令,PID的范围是0xC0~0xFF,具体的相关命令有:
Standard commands (STD)
Calibration commands (CAL)
. Page switching commands (PAG)
Data Acquisition and Stimulation commands (DAQ)
文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 排序 二【题目难度】 中等 三【题目编号】 274.H指数 四【题目描述】 给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。根据维基百科上 h 指数的定义:h 代表“高引用次数” ,一名科研人员的 h 指数 是指他(她)至少发表了 h 篇论文,并且每篇论文 至少 被引用 h 次。如果 h 有多种可能的值,h 指数 是其中最大的那个。 五【题目示例】 示例 1:
输入:citations = [3,0,6,1,5]输出:3解释:给定数组表示研究者总共有 5 篇论文,每篇论文相应的被引用了 3, 0, 6, 1, 5 次。由于研究者有 3 篇论文每篇 至少 被引用了 3 次,其余两篇论文每篇被引用 不多于 3 次,所以她的 h 指数是 3。 示例 2:
输入:citations = [1,3,1]输出:1 六【题目提示】 n = = c i t a t i o n s .
文章目录 📕 网络间的通信📕 socket 是什么1. socket 套接字2. 套接字描述符3. 基本的 socket 接口函数3.1 头文件3.2 socket() 函数3.3 bind() 函数struct sockaddr主机序列与网络序列 3.4 listen() 函数3.5 connect() 函数3.6 accept() 函数IP 地址风格转换区分两种套接字 3.7 read() 、write() 等函数3.8 close() 函数 📕 UDPudp_socket.hpp (封装 UdpSocket)udp_server.hpp (UDP 通用服务器)udp_client.hpp (UDP通用客户端) 📕 网络间的通信 前面的管道、共享内存等等进程间通信,都是仅限于用在本机进程之间通信。网络间进程通信要解决的是不同主机进程间的相互通信问题(可把同机进程通信看作是其中的特例)。
为此,首先要解决的是网络间进程标识问题。同一主机上,不同进程可用进程号(process ID)唯一标识。但在网络环境下,各主机独立分配的进程号不能唯一标识该进程。例如,主机A赋于某进程号5,在B机中也可以存在5号进程,因此,“5号进程” 这句话就没有意义了。 其次,操作系统支持的网络协议众多,不同协议的工作方式不同,地址格式也不同。因此,网间进程通信还要解决多重协议的识别问题。
TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口”可以唯一标识主机中的应用程序(进程)。这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的进程通信就可以利用这个标志与其它进程进行交互。
使用TCP/IP协议的应用程序通常采用应用编程接口:UNIX BSD的套接字(socket)和UNIX System V的TLI(已经被淘汰),来实现网络进程之间的通信。就目前而言,几乎所有的应用程序都是采用socket,而现在又是网络时代,网络中进程通信是无处不在,这就是为什么说“一切皆socket”。
📕 socket 是什么 1. socket 套接字 socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,都可以用 “打开open –> 读写write/read –> 关闭close” 模式来操作。Socket就是该模式的一个实现, socket 即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭).
说白了Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。
2. 套接字描述符 有关文件描述符,如果不了解,可以查看这篇文章: 文件描述符 。
最近在用 VScode 写代码的时候,发现 Python 代码不高亮显示:
这样用起来体验感不好,网上查询资料,可能存在的原因为:
安装Python扩展: 确保你已经安装了VS Code的Python扩展。如果没有安装,打开VS Code并在左侧的扩展面板中搜索"Python",然后选择并安装由Microsoft提供的"Python"扩展。选择正确的语言模式: 确保在VS Code底部状态栏中的语言模式选择器中选择了正确的语言,即Python。点击语言模式选择器,然后选择Python。检查文件扩展名: 确保你的Python文件的扩展名是".py",这有助于VS Code识别文件的语言类型。重启VS Code: 有时,VS Code可能需要重新启动才能正确加载语言扩展和高亮显示。检查VS Code设置: 确保你没有在VS Code的设置中禁用了代码高亮显示。你可以通过点击菜单中的"文件" > “首选项” > "设置"来访问设置界面,然后搜索"高亮显示"相关的设置。 Python拓展已经安装:
语言模式已经正确:
文件拓展名正确。
VScode的设置也没问题:
后来终于发现,是Python的Language Server出现了问题:
将其改为Pylance即可!
大功告成!
【目录】
文章目录 2. Series对象-一维数据1. 知识回顾-创建字典2. 调用库的类、函数、变量语法3. 实例化类创建一个对象4. Series一维数组5. pd.Series创建一个Series对象6. data = 列表7. 同时传入data和index8. data = 字典9. Series对象的3要素:索引+数据+类型9.1 data=列表,列表元素均为字符串9.2 data=列表,列表元素均为字符串+整数9.3 data=列表,列表元素均为整数9.4 data=列表,列表元素均为浮点数 10. Series类的values和index属性11. 利用index获取Series的索引12. 利用values获取Series的值13. 课堂练习14. 总结15. 课后练习 【正文】 2. Series对象-一维数据 【学习时间】
60分钟
1. 知识回顾-创建字典 【语法】
一个字典主要由5部分构成:
英文大括号{ } 字典的键 键与值之间用英文冒号:隔开 字典的值 键值对之间用英文逗号,分隔 code_dict字典名。字典用{ }大括号表示。注意集合也用{ }大括号表示。北京是字典键。:英文冒号。100000是字典的值。'北京':100000称为一个键值对。2个键值对之间用英文逗号,分隔。 【课堂练习】
创建一个字典。
字典的键为:姓名 和 性别。
姓名 对应的值是 ['张三', '李四', '王五']。
性别对应的值是 ['男','女','男']。
【代码示例】
# 字典的键为'姓名'和'年龄', # 字典的值为['张三', '李四', '王五']、['男','女','男'] my_dict = {'姓名': ['张三', '李四', '王五'], '性别': ['男','女','男']} # 打印字典 print(my_dict) 【终端输出】
1,通道 在进程中,可以通过管道的方式进行通信,在java线程中,也是可以通过管道的方式进行通信的。如一些文件的上传,可以直接在内存中通过管道的方式进行文件的上传,而不需要先将文件落盘到本地,再将文件上传到ftp服务器上,通过减少写入磁盘这一步骤,从而提高文件的上传效率,减少硬件和资源等的成本。
java中实现管道输入和输出的方式主要有四种,分别是PipedOutputStream、PipedInputStream、PipedReader 和 PipedWriter 。前面两种主要是针对二进制的字节流,后面两种主要是针对文本的字符流。
//构建输入流 PipedReader pipedReader = new PipedReader(); //构建输出流 PipedWriter pipedWriter = new PipedWriter(); try { //建立连接 pipedReader.connect(pipedWriter); } catch (IOException e) { e.printStackTrace(); } 并且在高并发中,这些管道流的操作都是属于线程安全的。
join 在日常开发中,比如说存在三个线程,分别是t1,t2,t3这三个线程,需求是想让t2在t1执行完后再执行,t3想再t2执行完后再执行。由于java中采用的是抢占式的线程调度方式,即不能手动的去操控线程的执行状况,因此在后面就出现了这个join 的方式。如下面的代码
public static void main(String[] args){ Thread t1 = new Thread(new Runnable() { @Override public void run() { try { //休眠2s Thread.sleep(2000); System.out.println(Thread.currentThread().getName()); } catch (InterruptedException e) { e.printStackTrace(); } } },"t1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { try { //加入join t1.
好久没更新博文了,去年备考了一年研究生,然后顺利上岸辽,今年九月份就要读研究生学开发了,以前本科学了一点点数据分析和爬虫的皮毛,希望以后在研究生继续努力学习,研究生阶段主打学习开发,所以自己也是零基础学习,更新下自己学习笔记吧,师从狂神yyds!
一:MyBatis简介 MyBatis是一款优秀的持久层框架,支持sql定制化、存储过程以及高级映射、避免了JDBC的繁琐操作、同时可以使用XML或者注解来进行开发配置操作数据库。
为什么需要使用MyBatis
1.方便
2.JDBC太复杂
3.让数据存入数据库更高效
4.不用MyBatis也可以。更容易上手。
(一):持久化 持久化:将数据在持久状态和瞬时状态进行转化的过程
内存:断点即失
为什么需要持久化?
有一些对象,不能让他丢掉;内存太贵;
(二):持久层 完成持久化的代码块层界限十分明显 二:MyBatis入门程序 思路:搭建环境->导入MaBatis->编写代码->测试
(一):搭建数据库 create database `mybatiss`; use `mybatiss`; create table `user`( `id` int(20) not null primary key, `name` varchar(20) default null, `pwd` varchar(20) default null )engine=INNODB default charset=utf8; insert into `user`(`id`,`name`,`pwd`) VALUES (11,'狂神aaa','123456'), (22,'狂神bbb','123356'), (33,'狂神ccc','124456'); (二):新建项目 1.新建一个普通的maven项目
2.删除src目录
3.导入maven依赖
<!-- 导入依赖--> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.33</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.
1. 学习编程语言和基础库 学习Python语言,掌握基础语法、函数、面向对象编程等概念学习Numpy库,用于科学计算和多维数组学习OpenCV库,包含了许多图像处理和计算机视觉算法学习TensorFlow/PyTorch,主要的深度学习框架 2. 学习数字图像处理算法 图像的表示方式(像素、灰度、二值化等)彩色空间转换(RGB、HSV等)滤波操作(均值滤波、高斯滤波、中值滤波等)形态学操作(腐蚀、膨胀、开运算、闭运算等)影像增强(直方图均衡化、自适应均衡化等)边缘检测算法(Sobel、Canny等)影像分割算法(区域生长、分水岭等) 3. 学习经典特征提取和机器学习算法 SIFT,SURF,ORB等特征检测和描述算法HOG,LBP等用于图像表示的特征SVM,KNN,决策树等机器学习算法 4. 深入学习卷积神经网络 卷积层、池化层等CNN基本结构LeNet、AlexNet、VGGNet、ResNet等CNN模型图像分类、目标检测等典型应用使用TensorFlow/PyTorch实现CNN模型 5. 实践项目练手 实现简单的物体分类器基于特征匹配的图像查找使用CNN进行手写数字识别基于深度学习的目标检测 6. 继续学习高级算法 更深度的神经网络(DenseNet、MobileNet等)生成对抗网络(GAN)实例分割算法(Mask R-CNN等)强化学习在计算机视觉的应用 7. 学习行业动态,参与开源项目 关注顶级会议最新研究进展(CVPR、ICCV等)参与Github上计算机视觉相关的开源项目发表论文投稿顶级学术会议
其实用dbeaver连接hive就可以了。但是呢,idea也有这个功能,本着研究下的想法就试试。
结果最后成功了 最后记录下。
参考文章。感觉不太行
PyCharm,idea通过插件database连接带Kerberos的hive_不饿同学的博客-CSDN博客
里面提到了两个解决办法,个人只习惯用第一个。
方法1 新增一个hive数据源 url填写 jdbc:hive2://cdp-node05.data.com:10000/;principal=hive/cdp-node05.data.com@CDP.COM;AuthMech=1;KrbRealm=CDH.COM;KrbHostFQDN=cdp-node05.data.com;KrbServiceName=hive;KrbAuthType=2
vm option填写
-Djavax.security.auth.useSubjectCredsOnly=false
-Djava.security.krb5.conf=C:\ProgramData\MIT\Kerberos5\krb5.ini
-Dsun.security.krb5.debug=true
方法2 url填写
jdbc:hive2://cdp-node06.data.com:10000/;principal=hive/cdp-node06.data.com@CDP.COM
vmoption 同上。。
——————————————————————————————————————————
然后使用起来也还行吧
备注遇到的问题 KrbException: Cannot locate default realm 这个就是idea根本不知道你的认证是啥,怎么认证?
-Djavax.security.auth.useSubjectCredsOnly=false
-Djava.security.krb5.conf=C:\ProgramData\MIT\Kerberos5\krb5.ini
-Dsun.security.krb5.debug=true
注意替换krb5.ini文件的位置
Peer indicated failure: GSS initiate failed 这个就是已经开始认证了,但是认证失败了。
jdbc:hive2://cdp-node06.data.com:10000/;principal=hive/cdp-node05.data.com@CDP.COM;AuthMech=1;KrbRealm=CDH.COM;KrbHostFQDN=cdp-node06.data.com;KrbServiceName=hive;KrbAuthType=2
因为改错。一个node05 一个node06.。。。
最近重装idea了,发现我按照之前的居然也连不上了 cao
class not find这种报错 经过google一番,在hive的driver添加如下jar包,就可以了。不一定全有用,自己试吧。我添加jar包是因为连接报错都是class not find之类的错误
若帮助到你,点个赞是对我最大的支持
第一步:在菜单栏option->File Type Options
第二步:在File Type Options ->C/++ Source file ->Auto Indent...
第三步:在弹出框中把 indent Open Brace 与 indent close brace 勾选去掉
目录 前言1. What、Why and How1.1 What1.2 Why1.3 How 2. 安装3. 创建新项目4. 配置OpenCV库4.1 下载opencv安装包4.2 配置系统环境变量4.3 VS项目环境配置4.4 总结 5. 已有项目添加6. Tips6.1 常用快捷键6.2 字体和颜色选择6.3 配置编译路径 结语下载链接参考 前言 最近因为项目需求,需要在 Windows 下开发一个 C++ 项目,博主之前都是在 Linux 上开发的,突然转到 Windows 多少还是有点不适应的。本次使用的 IDE 是 Visual Studio,之前有简单使用过,但是很多都忘记了,故此做个记录,方便下次查看。
本文主要针对 Visual Studio 2017 的安装和项目配置进行简单的分享,若有问题欢迎各位看官批评指正!!!😄
1. What、Why and How 1.1 What Visual Studio 是什么?
Visual Studio(简称 VS)是美国微软公司的开发工具包系列产品,是一个集成的开发环境,相对来说比较完整,它包括了整个软件生命周期中所需要的大部分工具,如代码完成工具、编译器、图形设计器、UML工具、代码管控工具、集成开发环境(IDE)等等,以简化开发人员构建应用程序的过程。通俗的讲,是一款编译器。
要注意的是,它虽然和 Visual Studio Code 名字非常相近,但两者完全不是同一个东西!!!
Visual Studio Code (简称 VSCode)是美国微软公司开发的一个项目,是一款现代化开源的、免费的、跨平台的、高性能的、轻量级的代码编辑器。通俗地讲,它是一款超级的文本编辑器。
参考自:Visual Studio和Visual Studio Code(VSCode)的区别及如何选择
1.2 Why 为什么要学习安装和配置 Visual Studio?
一.修改配置文件(dhcpcd或NetworkManager) 1.如果是dhcpcd文件服务: 使用以下命令打开配置文件: sudo nano /etc/dhcpcd.conf 之后在配置文件的底部增加以下配置:
interface wlan0 static ip_address=192.168.1.199/24 static routers=192.168.1.1 static domain_name_servers=8.8.8.8 static domain_search=114.114.114.114 interface eth0 static ip_address=192.168.2.194/24 static routers=192.168.2.1 static domain_name_servers=8.8.8.8 static domain_search=114.114.114.114 其中,wlan0是无线网络配置项,eth0是有线网络配置。
之后重启树莓派:
reboot 注意:
ip地址按需要修改,路由地址和ip相匹配,另外两项也可以设置为路由地址。
2.如果是Network-Manager网络服务: 设置静态 IP:
sudo nmcli connection modify ipv4.addresses 192.168.1.101/24 ipv4.method manual 设置网关地址:
sudo nmcli connection modify ipv4.gateway 192.168.1.1 如果设置动态获取 IP:
sudo nmcli connection modify ipv4.method auto 3.两种配置转换:
如果你不喜欢dhcpcd方式或者Network-Manager方式配置网络,想换另一种方式去配置,可以根据一下几行命令解决(注意斜杠:区分好你要停掉或修改的配置):
sudo systemctl stop dhcpcd/Network-Manager sudo disable dhcpcd/Network-Manager sudo enable Network-Manager/dhcpcd reboot 二、修改第二种配置文件(dhcpcd) 使用以下命令打开配置文件:
apk 静默安装 - 欧颜柳 - 博客园 (cnblogs.com) 如果需要应用进行静默安装,则需要满足一下两个条件
1 必须添加权限 <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
2 必须是系统应用,或者系统签名应用
方法 1 通过 adb install 安装
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
chrome://dino/
1.【无敌】Runner.instance_.gameOver=function(){}
2.【疾跑】Runner.instance_.setSpeed(50)
3.【高跳】Runner.instance_.tRex.setJumpVelocity(20)
简介
旅行商问题(Traveling Salesman Problem, TSP)是组合优化中的经典问题。简单地说,一个旅行商需要访问N个城市,并返回到出发城市,问题是找到最短的可能路线,使得每个城市只被访问一次。由于TSP是一个NP-hard问题,找到其精确解决方案是非常计算密集型的,特别是对于大规模的城市集。因此,我们需要一种可以在合理的时间内得到近似解的方法。
模拟退火算法(Simulated Annealing, SA)是一个非常受欢迎的随机搜索技术,用于求解优化问题。模拟退火是受固体退火过程启发的一种算法,通过不断比较当前解和新解来找到问题的近似解。
在本文中,我们将介绍如何使用模拟退火算法解决TSP问题,并提供Python代码的实现。
模拟退火算法概述
模拟退火算法的基本思想是从一个随机解开始,然后在每一步尝试一个新解。如果新解比当前解好,我们接受它。如果新解不如当前解,我们以某个概率接受它,这个概率随着时间的推移而减小,模拟固体材料在冷却过程中的退火过程。
模拟退火的步骤如下:
选择一个初始解 sss 和一个初始温度 TTT。在当前温度下重复以下步骤若干次: 选择一个在当前解附近的新解 s′s’s′。如果 s′s’s′ 比 sss 好,或者以某个概率接受 s′s’s′(这个概率与 TTT 和两个解之间的差异有关),则将 s′s’s′ 设置为当前解。 降低温度 TTT。重复步骤2,直到满足某个停止条件。 Python实现
首先,我们需要定义一些辅助函数,如计算距离和总旅行距离。
import numpy as np def distance(city1, city2): """计算两个城市之间的欧几里得距离""" return np.sqrt((city1[0] - city2[0])**2 + (city1[1] - city2[1])**2) def total_distance(tour, cities): """计算给定路线的总距离""" n = len(tour) return sum(distance(cities[tour[i]], cities[tour[(i+1) % n]]) for i in range(n)) 其中,cities是一个列表,每个元素都是一个表示城市坐标的元组。tour是一个表示旅行顺序的整数列表。
例如,对于以下城市列表:
cities = [(0,0), (1,2), (2,4), (3,1)] 一个可能的旅行路线是 [0, 1, 2, 3],代表从第一个城市开始,经过第二、第三和第四个城市,然后返回第一个城市。
抽象类可以代码复用,将一些需要差异化的逻辑抽出一个抽象方法,其他子类可以继承该抽象类,实现对应的逻辑,这样就可以复用其他不需要差异化表达的代码逻辑。
public class Father{ public void survive(){ //公用逻辑 getFood(); //公用逻辑 } //抽象方法,不同的子类有着不同的逻辑,继承该抽象类,实现对应的逻辑就好了。 public abstract getFood(); }
第一步:引入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> <version>2.2.5.RELEASE</version> </dependency> 第二步:配置yml文件,在spring下面加上这个 elasticsearch: rest: # ip是服务器ip地址 uris: http://127.0.0.1:9200 然后启动项目,看到出现这个就是成功了
第三步: 创建一个常量类,用于存储我们一会儿要用到的名称 public class OrderEs { public static final String INDEX_NAME = "order_index"; public static final String ID = "id"; public static final String ORDER_NO = "order_no"; public static final String ORDER_BUYER = "order_buyer"; public static final String ORDER_PHONE = "order_phone"; public static final String REAL_PAY = "real_pay"; public static final String ACCOUNT = "account"; } 第四步:创建Es实体类,注意要加上@Document注解 @Document(indexName = OrderEs.
注意:此方案仅适用于windows系统哦!!! 这是一篇姗姗来迟的文章,一直在使用,但是一直没时间做一下总结,今天抽空就分享给大家,操作很简单,耐心跟着操作一下。
做前后端分离的开发的时候,出于一些原因往往需要将浏览器设置成支持跨域的模式,而且chrome浏览器支持可跨域的设置,但是新版本的chrome浏览器提高了跨域设置的门槛,原来的方法不再适用了。其实网上也有很多大神总结的chrome跨域设置教程,都是差不多。
个人开发中的使用习惯 下载好谷歌浏览器以后,快捷方式我会复制两份放在桌面上,这时候两个是一模一样的,我会将其中一个重命名(我是跨域的命名为 dev),另外一个正常命名,然后在对命名为“dev”的浏览器打开方式进行寡跨域设置,这样我们就会拥有一个正常的浏览器,一个跨域的浏览器啦~
老版本Chrome浏览器(版本号49之前的跨域设置) 1、右键点击谷歌浏览器,选择属性
2、 在目标输入框尾部加上 --disable-web-security
注意:这里 --disable-web-security 前面有一个空格
3.点击应用和确定后关闭属性页面,并打开chrome浏览器。如果浏览器出现提示“你使用的是不受支持的命令标记 --disable-web-security”,那么说明配置成功。
新版浏览器跨域设置(版本号49之后的跨域设置) 1、在电脑上新建一个目录(任意位置) 例如 C:\MyChromeDevUserData
2、右键点击谷歌浏览器,选择属性;
3、在目标输入框尾部加上 --disable-web-security --user-data-dir=C:\MyChromeDevUserData
注意:
1.两个 -- 前面都是有空格的哦~
2. 如果目标地址原先有引号,那么 --disable-web-security --user-data-dir=C:\MyChromeDevUserData 要加在引号外面。
4、点击应用和确定后关闭属性页面,并打开chrome浏览器。
再次打开chrome,发现有“--disable-web-security”相关的提示,说明chrome就能正常跨域工作了。
文章目录 01 前言02 安装03 修改配置3.1 安装vim插件3.2 修改用户密码 04 验证 01 前言 clickhouse docker hub首页:https://hub.docker.com/r/yandex/clickhouse-server,这里描述了clickhouse在docker下的简介以及部署方式:
搜索自己需要的版本:https://hub.docker.com/r/yandex/clickhouse-server/tags?page=1:
访问:https://hub.docker.com/r/yandex/clickhouse-server/dockerfile查看dockerfile,内容如下(已添加注释):
# 使用基础镜像为 Ubuntu 18.04 FROM ubuntu:18.04 # 设置构建参数:ClickHouse仓库、版本和gosu版本 ARG repository="deb http://repo.yandex.ru/clickhouse/deb/stable/ main/" ARG version=19.1.13 ARG gosu_ver=1.10 # 更新APT源,并安装所需软件和依赖 RUN apt-get update \ && apt-get install --yes --no-install-recommends \ apt-transport-https \ dirmngr \ gnupg \ && mkdir -p /etc/apt/sources.list.d \ && apt-key adv --keyserver keyserver.ubuntu.com --recv E0C56BD4 \ && echo $repository > /etc/apt/sources.list.d/clickhouse.list \ && apt-get update \ && env DEBIAN_FRONTEND=noninteractive \ apt-get install --allow-unauthenticated --yes --no-install-recommends \ clickhouse-common-static=$version \ clickhouse-client=$version \ clickhouse-server=$version \ libgcc-7-dev \ locales \ tzdata \ wget \ && rm -rf \ /var/lib/apt/lists/* \ /var/cache/debconf \ /tmp/* \ && apt-get clean # 下载并安装gosu工具 ADD https://github.
#include <iostream> #include <fcntl.h> #include <termios.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main() { int serial_port = open("/dev/ttyS0", O_RDONLY); if (serial_port < 0) { std::cerr << "Failed to open serial port" << std::endl; return -1; } struct termios tty; struct termios tty_old; memset(&tty, 0, sizeof(tty)); if (tcgetattr(serial_port, &tty) != 0) { std::cerr << "Failed to get serial port attributes" << std::endl; return -1; } tty_old = tty; //波特率设置为9600,可以根据具体需求更改 cfsetospeed(&tty, (speed_t)B9600); cfsetispeed(&tty, (speed_t)B9600); tty.
使用ChatGPT快速制作播客和其他长篇内容是一个高效且具有一定创造性的过程。以下是一些详细的步骤和技巧,以帮助你充分利用ChatGPT来制作高质量的内容。
一、准备阶段 确定主题或话题:在开始制作之前,你需要明确你的播客或长篇内容将聚焦的主题或话题。确保选择的主题或话题具有吸引力,并思考如何让听众产生兴趣。
设定目标:明确你想要传达的信息、目标受众以及你希望听众从你的内容中获得什么。这将有助于你为制作过程设定明确的方向。
编写提示:为了引导ChatGPT生成内容,你需要编写清晰的提示。对于播客,你可以列出要讨论的主题、关键点以及你希望涵盖的细节。对于长篇内容,你可以列出要讨论的主题、关键点、例证、论据等。确保你的提示能够清晰地描述任务的目标和范围。
搜集素材:在开始生成内容之前,搜集相关的素材和参考资源,包括文章、研究报告、数据等。这将有助于提供给ChatGPT更多的上下文和信息,从而生成更准确、有趣的内容。
二、使用ChatGPT生成内容 输入提示:在对话界面中,输入你的提示。确保提供足够的信息,让ChatGPT理解任务的目标和要求。例如,对于播客,你可以输入类似于“讨论人工智能对未来的影响,包括其优点和潜在问题”的提示。
调整提示:根据ChatGPT的回答,你可以逐步调整提示,以获得更好的结果。如果你觉得生成的文本与你的期望不符,可以尝试调整提示,或者提供更多的上下文和信息。
生成内容:一旦你满意ChatGPT的回答,可以点击"Done"按钮来生成相应的内容。对于播客,你可以将生成的文本录制下来。对于长篇内容,你可以直接复制和粘贴生成的文本。
三、编辑和完善内容 检查语法和拼写:ChatGPT生成的内容可能存在语法和拼写错误,因此在进行发布之前,务必检查和修正这些错误。使用语法和拼写检查工具(如Grammarly)可以帮助你快速发现并修正这些错误。
调整逻辑结构:虽然ChatGPT尽力生成连贯的文本,但有时内容的逻辑结构可能不够清晰。在这种情况下,你可以手动调整文本的逻辑结构,确保观点和论点之间的联系更加紧密。
添加个人风格:尽管ChatGPT能够生成高质量的文本,但内容可能缺乏你个人的风格和特色。因此,在编辑和完善过程中,你可以添加自己的语言和风格,使内容更具独特性和个性化。
四、发布和分享内容 选择平台:根据你的内容类型和目标受众,选择合适的发布平台。对于播客,你可以选择像Podbean或Spotify这样的播客平台。对于长篇内容,你可以选择将文本发布到你的网站、博客或社交媒体上。
宣传和推广:一旦你的内容准备就绪,你可以通过社交媒体和其他渠道宣传和推广你的作品。分享你的链接并吸引潜在的听众和读者。
总之,使用ChatGPT制作播客和其他长篇内容是一个相对快速且具有创造性的过程。通过明确主题和目标、编写清晰的提示以及编辑和完善内容,你可以生成高质量的内容并将其分享给更多的听众。
当你遇到电脑提示“无法定位程序输入点于XXX动态链接库”的情况是不是不知道怎么解决?其实信息就藏在提示框里,下面看看小编是如何解决无法定位程序输入点于动态链接库的吧。
1、首先查看提示框内缺少的是什么dll文件。
2、例如是Qt5gui.dll文件丢失,直接在百度搜索这个文件下载。
3、下载之后直接双击安装,然后重启电脑。
4、再次执行之前的操作,已经不再提示“无法定位程序输入点于XXX动态链接库”,因为已经把丢失的文件安装到电脑了。
以上就是电脑提示“无法定位程序输入点于XXX动态链接库”的解决方法。
Simple Screen Recorder
优点:
录制OpenGl应用程序不需要额外下载解码器;
低配电脑自动降帧;
随用随录,操作任性;
声音扩展性功能;
可选择录制编码器;
显示录制文件大小,心里有底。
安装:
sudo add-apt-repository ppa:maarten-baert/simplescreenrecorder # 添加源 sudo apt-get update # 更新源 sudo apt-get install simplescreenrecorder # 安装 打开:
参考:
1、Ubuntu下三个实用的录屏软件
https://www.cnblogs.com/cherishry/p/5710612.html
2、Ubuntu(Linux)使用SimpleScreenRecorder录屏
Ubuntu(Linux)使用SimpleScreenRecorder录屏-百度经验
前言:Hello大家好,我是小哥谈。腐蚀和膨胀是图像形态学中的两种核心操作,通过这两种操作可以清除或者强化图像中的细节。本节课就对OpenCV中的腐蚀和膨胀操作进行详细的介绍。🌈
前期回顾:
史上最全OpenCV常用方法及使用说明汇总,建议收藏!
OpenCV基础知识(1)— OpenCV概述
OpenCV基础知识(2)— 图像处理的基本操作(读取图像、显示图像、保存图像和获取图像属性)
OpenCV基础知识(3)— 图像数字化基础(像素、色彩空间)
OpenCV基础知识(4)— 绘制图形(线段、矩形、圆形、多边形和文字)
OpenCV基础知识(5)— 几何变换(缩放、翻转、旋转和透视)
OpenCV基础知识(6)— 滤波器(均值滤波器、中值滤波器、高斯滤波器和双边滤波器) 目录
🚀1.腐蚀 🚀2.膨胀
🚀3.总结
🚀1.腐蚀 腐蚀操作可以让图像沿着自己的边界向内收缩。OpenCV通过“核”来实现收缩计算。“核”的英文名为kernel,在形态学中可以理解为“由n个像素组成的像素块”,像素块包含一个核心(核心通常在中央位置,也可以定义在其他位置)。像素块会在图像的边缘移动,在移动过程中,核会将图像边缘那些与核重合但又没有越过核心的像素点都抹除,就像削土豆皮一样,将图像一层一层地“削薄”。🌴
OpenCV将腐蚀操作封装成erode()方法,该方法的语法如下:
dst = cv2.erode(src,kernel,anchor,iterations,borderType,borderValue) 参数说明:
src:原始图像
kernel:腐蚀使用的核
anchor:可选参数,核的锚点位置。
iterations:可选参数,腐蚀操作的迭代次数,默认值为1。
borderType:可选参数,边界样式,建议默认。
borderValue:可选参数,边界值,建议默认。
返回值说明:
dst:经过腐蚀之后的图像
在OpenCV做腐蚀或者其他形态学操作时,通常使用Numpy模块来创建核数组,例如:
import numpy as np k = np.ones((5,5),np.uint8) 这两行代码就是通过Numpy模块的ones()方法创建一个5行5列(简称5*5)、数字类型为无符号8位整数、每一个数字的值都是1的数组,这个数组就可以当做erode()方法的核参数。除了5×5的结构,还可以使用3×3、9×9、11×11等结构,行列数越大,计算出的效果就越粗糙,行列数越小,计算出的效果就越精细。🍁
案例:
使用3*3的核对仙人球图像进行腐蚀操作,可以将图像里的刺抹除掉,具体代码如下:
import cv2 import numpy as np img = cv2.imread("cactus.jpg") # 读取原图 k = np.ones((3, 3), np.uint8) # 创建3*3的数组作为核 cv2.imshow("img", img) # 显示原图 dst = cv2.
前言:Hello大家好,我是小哥谈。OpenCV提供了许多用于绘制图形的方法,包括绘制线段的line()方法、绘制矩形的retangle()方法、绘制圆形的circle()方法、绘制多边形的polylines()方法和绘制文字的putText()方法。本节课将依次对上述各个方法进行讲解,并使用上述方法绘制相应的图形。 🌈
前期回顾:
史上最全OpenCV常用方法及使用说明汇总,建议收藏!
OpenCV基础知识(1)— OpenCV概述
OpenCV基础知识(2)— 图像处理的基本操作(读取图像、显示图像、保存图像和获取图像属性)
OpenCV基础知识(3)— 图像数字化基础(像素、色彩空间)
目录
🚀1.线段的绘制 🚀2.矩形的绘制
🚀3.圆形的绘制
🚀4.多边形的绘制
🚀5.文字的绘制
🚀1.线段的绘制 Opencv提供了用于绘制线段的line()方法,使用这个方法即可绘制长短不一的、粗细各异的、五颜六色的线段。🌱
line()方法语法格式如下:
img = cv2.line(img,pt1,pt2,color,thickness) 参数说明:
img:画布
pt1:线段的起点坐标
pt2:线段的终点坐标
color:绘制线段时的线条颜色
thickness:绘制线段的线条宽度
说明:♨️♨️♨️
当线条颜色是红色的时候,由于Opencv默认的通道顺序是B-G-R,因此将使用(0,0,255)表示红色。
Python代码:
import numpy as np # 导入Python中的numpy模块 import cv2 # np.zeros():创建了一个画布 # (300, 300, 3):一个300 x 300,具有3个颜色空间(即Red、Green和Blue)的画布 # np.uint8:OpenCV中的灰度图像和RGB图像都是以uint8存储的,因此这里的类型也是uint8 canvas = np.zeros((300, 300, 3), np.uint8) # 在画布上,绘制一条起点坐标为(50, 150)、终点坐标为(250, 150),绿色的,线条宽度为10的线段 canvas = cv2.line(canvas, (50, 150), (250, 150), (0, 255, 0), 10) # 在画布上,绘制一条起点坐标为(50, 250)、终点坐标为(250, 250),红色的,线条宽度为15的线段 canvas = cv2.
java //加 base64 = new BASE64Encoder().encode(str.getBytes()); //解 str = new String(new BASE64Decoder().decodeBuffer(base64)); JavaScript //加 base64 = btoa(str); // IE 10- 需要引入 base64.js 且不支持汉字 //或 var s = CryptoJS.enc.Utf8.parse(str); base64 = CryptoJS.enc.Base64.stringify(s); // 需要引入 CryptoJS //解 str = atob(base64); // IE 10- 需要引入 base64.js 且不支持汉字 //或 var s = CryptoJS.enc.Base64.parse(base64); str = s.toString(CryptoJS.enc.Utf8); // 需要引入 CryptoJS Python import base64 # 加 base64 = base64.b64encode(str) # 解 str = base64.b64decode(base64) PHP //加 $base64 = base64_encode($str); //解 $str = base64_decode($base64); GO //加 import b64 "
1.MERRA-2数据下载 网址:https://gmao.gsfc.nasa.gov/reanalysis/MERRA-2/ 第一步,打开网站
第二步:点击Data Access-MDISC进入数据集选择
第三步:登录个人账号,输入想搜索数据集版本号(后边有版本号对应数据及数据解释的链接),或者根据自己需求在左边选择。
如果不知道版本号可以查看《README Document for MERRA-2 Data Products》手册
第四步:数据批量下载,需使用插件Down Them All插件(下载地址:https://www.downthemall.net/,该插件目前只支持Firefox、Chrome、Opera三个浏览器,建议使用谷歌浏览器),不建议使用weget下载,对网络要求高,并且cmd有时候会进不去服务器
选中需要下载的数据(建议如果研究时间长按照年选择,如果研究时间段按月选择),右键使用点击用DownThemAll保存选中项
点击所有文件后选择下载,就开始下载了,下载位置为浏览器默认下载位置,可以更改!
2.提取所需指标并转为TIFF(RStudio) 代码如下
library(terra) library(tidyverse) library(sf) rast("D:/data/merra2_dust original data/M2TMNXAER.5.12.4ːMERRA2_100.tavgM_2d_aer_Nx.198001.nc4") -> rst rst # raster::raster("mydata/M2TMNXAER.5.12.4ːMERRA2_100.tavgM_2d_aer_Nx.198001.nc4", varname = "BCSCATAU") -> rsttemp # plot(rsttemp) # # terra::ext(rst) <- terra::ext(rsttemp) # terra::crs(rst) <- terra::crs(rsttemp) %>% st_crs() %>% .$proj4string # rst rst$DUSMASS %>% writeRaster("temp.tif") # 循环所有的文件 # 使用 str_extract 可以提取月份: str_extract("D:/data/merra2_dust original data//M2TMNXAER.5.12.4ːMERRA2_100.tavgM_2d_aer_Nx.198001.nc4", "\\d{6}") -> month # 使用 fs::dir_ls() 可以索引所有的文件,假设所有的文件都在 mydata 文件夹里面 fs::dir_ls("
文章目录 1.格式化主体风格占位符 2.代码行行长度换行方式不必要的空行括号和空格行数 3.字符串4.依赖管理依赖规范import 规范 5.初始化初始化 struct初始化 map初始化 slice申明变量避免使用 init() 6.错误处理书写风格error 处理panic 处理recover 处理类型断言 7.注释通用包注释函数注释结构体注释变量和常量注释类型注释接口注释 8.命名规范通用规则项目命名包命名文件命名函数命名结构体命名接口命名量命名通用常量命名 方法接收器命名错误命名避免使用内置名称 9.流程控制ifforrangeswitchreturngoto程序退出方式 10.函数入参&返回值成员函数局部变量defer减少嵌套(圈复杂度)魔法字面量函数分组与顺序 11.单元测试12.杂项12.1 基本类型偏执通用场景结构体 12.2 单一职责包&文件函数 12.3 goroutine12.4 应用服务12.5 常用工具 参考文献 !!! 提示:本文停止更新,内容已迁移至开源书籍 《Go 编码建议》,欢迎大家协同共建。
为形成统一的 Go 编码风格,提高代码的可读性、可靠性和易维护性,在官方 Google Go Code Review Comments 的基础上,给出编码风格建议。使用时,可根据实际情况进行了调整和补充。
1.格式化 主体风格 代码必须用 gofmt 工具格式化。 gofmt 使用制表符进行缩进,使用空白符进行对齐。
IDE 在保存代码时可设置自动执行 gofmt,如 GoLand 的 Settings > Tools > File Watchers 中可勾选 go fmt 并指定作用范围。
占位符 通过%v打印错误信息,%v前建议加冒号。 // Bad logger.Errorf("num %d, err %s"
一、MAT下载和安装 1、概述 MAT(Memory Analyzer Tool)工具是一款功能强大的]ava堆内存分析器。可以用于查找内存泄漏以及查看内存消耗情况。MAT是基于Eclipse开发的,不仅可以单独使用,还可以作为插件的形式嵌入在Eclipse中使用。是一款免费的性能分析工具,使用起来非常方便。
2、下载地址: https://www.eclipse.org/mat/downloads.php
我目前电脑的JDK安装环境是1.8的,所以需要下载对应JDK1.8版本的MAT版本
3、安装 下载后解压,点击MemoryAnalyzer.exe进行启动
4、安装出现的报错问题 4.1、MAT版本和JDK版本不一致 问题描述:
要是直接下载最新版的MAT,可能需要高版本JDK才行。启动是需要JDK11或者更高的版本,我本地JDK版本是1.8,所以会报JDK版本不适合。
解决方法:
在MemoryAnalyzer.ini 中加入指定jdk的地址, (jdk不用安装直接下载 解压指定bin/javaw.exe就可)
-vm D:/java/jdk1.8.0_211/binbin/javaw.exe -vm D:/java/jdk1.8.0_211/binbin/javaw.exe -startup plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar --launcher.library plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.700.v20180518-1200 -vmargs -Xmx1024m 4.2、堆dump文件较大、使用MAT打开的时候总是抛出 Java Heap Error 问题描述:
有时候线上产生的堆dump文件较大,如果你的hprof文件没有问题的话,使用MAT打开的时候总是抛出 Java Heap Error. 可能是默认的1024m内存不够用了。
解决办法:
找到MAT的安装目录,找到MemoryAnalyzer.ini 修改其中的-Xmx即可
将-Xmx1024m 调大即可
5、jmap命令拿到dump日志文件 jmap是Java虚拟机自带的一个命令行工具,可以用来生成JVM内存快照(Heap dump)文件。以下是使用jmap命令生成dump文件的步骤:
jmap -dump:format=b,file=heap.bin <pid> 通常情况下,在生产环境中使用jmap命令生成Heap dump文件时,建议把生成的文件下载到本地进行分析,以减少对生产环境的干扰。另外,在生成Heap dump文件时,一定要确保Java应用程序正常运行,否则可能会导致生成的文件不完整或者无法正确解析。
二、MAT工具排查分析OOM 1、故障现象: 集群应用服务器在高并发请求的情况下会不定时地因为响应超时而报警,但是很快又超时解除,恢复正常,如此反复,让运维人员非常苦恼。
原因分析: 来到一家新公司,一个重构项目的开发人员估计搞不动了,最后选择跑路,我的到来正好接盘了这个有好多bug的项目。配合测试功能测试完结束后,进行压测。发现查询接口只要并发一起来就会出现错乱的现象。先是排查原先写的代码是否有问题,没发现问题,然后我以为是脏读,调整的事务的隔离级别等等方法,发现还是解决不了。最后没办法在方法上加了一个synchronized锁,再进行压测时,虽然吞吐量不高,但是不会有报错的现象。等开始正式切换系统进行上线时。因为每天会有至少20w的查询量。只要某个时间段只要请求量很高就会出现连接超时的现象。当时也想到是因为加了synchronized造成高并发请求下,很多请求一直在等待,最后因为时间太久而造成的超时。所以我就下载了dump文件,使用MAT工具进行分析。果然是这个锁造成的。这是的我已经对代码稍微熟悉了,分析什么造成的错乱现象。发现代码有一处用到了共享变量,造成每次高并发去请求出现的错乱现象。我当时心里。。。
参考https://blog.csdn.net/cl939974883/article/details/124581664 文档,确实是synchronized造成的
下面详说一下MAT如何分析dump文件
2、MAT 分析 OOM 问题通常思路: 通过支配树功能或直方图功能查看消耗内存最大的类型,来分析内存泄露的大概原因;查看那些消耗内存最大的类型、详细的对象明细列表,以及它们的引用链,来定位内存泄露的具体点;配合查看对象属性的功能,可以脱离源码看到对象的各种属性的值和依赖关系,帮助我们理清程序逻辑和参数;辅助使用查看线程栈来看 OOM 问题是否和过多线程有关,甚至可以在线程栈看到 OOM 最后一刻出现异常的线程。 3、使用MAT定位问题: 定位问题方式一:
目录
一、什么是线程?它与进程有什么区别?为什么要使用多线程?
二、 同步和异步有什么区别?
三、如何实现Java多线程?
(1)继承Thread类,重写run()方法
(2)实现Runnable接口,并实现该接口的run()方法
(3)实现Callable接口,重写call()方法
四、一个类是否可以同时继承Thread与实现Runnable接口?
五、run()方法与start()方法有什么区别?
六、多线程同步的实现方法有哪些?
(1)synchronized关键字
(2)wait()方法与notify()方法
(3)Lock
七、sleep()方法与wait()方法有什么区别?
八、sleep()方法与yield()方法有什么区别?
九、终止线程的方法有哪些?
十、synchronized与Lock有什么异同?
十一、什么是守护线程?
十二、 join()方法的作用是什么?
一、什么是线程?它与进程有什么区别?为什么要使用多线程? 线程是指程序在执行过程中,能够执行程序代码的一个执行单元。在Java语言中,线程有4种状态:运行、就绪、挂起和结束。
进程是指一段正在执行的程序。而线程有时也被称为轻量级进程,它是程序执行的最小单元,一个进程可以拥有多个线程,各个线程之间共享程序的内存空间(代码段、数据段和堆空间)及一些进程级的资源(例如打开的文件),但是各个线程拥有自己的栈空间。
在操作系统级别上,程序的执行都是以进程为单位的,而每个进程中通常都会有多个线程互不影响地并发执行,那么为什么要使用多线程呢?原因有以下几个方面的内容:
1)使用多线程可以减少程序的响应时间。在单线程(单线程指的是程序执行过程中只有一个有效操作的序列,不同操作之间都有明确的执行先后顺序)的情况下,如果某个操作很耗时,或者陷入长时间的等待(如等待网络响应),此时程序将不会响应鼠标和键盘等操作,使用多线程后,可以把这个耗时的线程分配到一个单独的线程去执行,从而使程序具备了更好的交互性。
2)与进程相比,线程的创建和切换开销更小。由于启动一个新的线程必须给这个线程分配独立的地址空间,建立许多数据结构来维护线程代码段、数据段等信息,而运行于同一进程内的线程共享代码段、数据段,线程的启动或切换的开销比进程要少很多。同时多线程在数据共享方面效率非常高。
3)多CPU或多核计算机本身就具有执行多线程的能力,如果使用单个线程,将无法重复利用计算机资源,造成资源的巨大浪费。因此在多CPU计算机上使用多线程能提高CPU的利用率。
4)使用多线程能简化程序的结构,使程序便于理解和维护。一个非常复杂的进程可以分成多个线程来执行。
二、 同步和异步有什么区别? 在多线程的环境中,经常会碰到数据的共享问题,即当多个线程需要访问同一个资源时,它们需要以某种顺序来确保该资源在某一时刻只能被一个线程使用,否则,程序的运行结果将会是不可预料的,在这种情况下就必须对数据进行同步,例如多个线程同时对同一数据进行写操作,即当线程A需要使用某个资源时,如果这个资源正在被线程B使用,同步机制就会让线程A一直等待下去,直到线程B结束对该资源的使用后,线程A才能使用这个资源,由此可见,同步机制能够保证资源的安全。
要想实现同步操作,必须要获得每一个线程对象的锁。获得它可以保证在同一时刻只有一个线程能够进入临界区(访问互斥资源的代码块),并且在这个锁被释放之前,其他线程就不能再进入这个临界区。如果还有其他线程想要获得该对象的锁,只能进入等待队列等待。只有当拥有该对象锁的线程退出临界区时,锁才会被释放,等待队列中优先级最高的线程才能获得该锁,从而进入共享代码区。
Java语言在同步机制中提供了语言级的支持,可以通过使用synchronized关键字来实现同步,它是以很大的系统开销作为代价的,有时候甚至可能造成死锁,所以,同步控制并非越多越好,要尽量避免无谓的同步控制。实现同步的方式有两种:一种是利用同步代码块来实现同步;另一种是利用同步方法来实现同步。
异步与非阻塞类似,由于每个线程都包含了运行时自身所需要的数据或方法,因此,在进行输入输出处理时,不必关心其他线程的状态或行为,也不必等到输入输出处理完毕才返回。当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,异步能够提高程序的效率。
三、如何实现Java多线程? Java虚拟机允许应用程序并发地运行多个线程。在Java语言中,多线程的实现一般有以下3种方法,其中前两种为最常用的方法。
(1)继承Thread类,重写run()方法 Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()方法。start()方法是一个native(本地)方法,它将启动一个新线程,并执行run()方法(Thread中提供的run()方法是一个空方法)。这种方式通过自定义直接extend Thread,并重写run()方法,就可以启动新线程并执行自己定义的run()方法。需要注意的是,调用start()方法后并不是立即执行多线程代码,而是使得该线程变为可运行态(Runnable),什么时候运行多线程代码是由操作系统决定的
public class test { public static void main(String[] args) { MyThread thread = new MyThread(); thread.start();//开启线程 } public static class MyThread extends Thread{ public void run(){ System.out.println(" Thread body");//线程的函数体 } } } 输出结果:
主打一个用尽可能少的代码,达成我们的目的
频谱图 1.工具箱实现。想必电气小伙伴们一定(是吗?)了解powergui中的FFT analysis工具。注:R2022b(或其它较高版本)可以在命令行窗口用代码powerFFT 或 power_fftscope代码调出APP。
不了解怎么使用的小伙伴,请点击上图左上角的Help按钮查看官方详细帮助文档,下面展示一下使用效果:
2.代码实现。小伙伴们是否有过想把FFT分析结果图导出但奈何没有导出选项的苦恼(截图??)。在较低matalb版本(比如2018版)中的FFT analysis工具箱中是有菜单栏的,里面就包括了导出功能,然而高版本(2022版)中就只剩光秃秃的一个Help选项。
看来只能用代码分析绘图了。
正确的matlab使用者应该具备 有,绝不自己写的“觉悟”,不然岂不是“辜负”了官方的“Less code. More research.”初衷
matlab的工具箱一般包括GUI(APP)和相关函数两块,一般GUI(APP)是基于相关函数开发的。而FFT Analyzer APP的主体分析功能就是基于power_fftscope函数实现的。
通过一个使用案例,介绍这个函数与APP使用的对应关系:
% 初始化操作 % 用函数默认设置对VIwave变量中的数据进行FFT分析,分析结果返回给FFTDdata [FFTdata] = power_fftscope(VIwave); FFTdata.input = 1; % 对应APP Signal FFTdata.signal = 1; % 对应APP Dimension FFTdata.startTime = 0.75; % 对应APP Start Time (s) FFTdata.cycles = 40; % 对应APP Number of cycles FFTdata.fundamental = 50; % 对应APP Fundamental frequency (Hz) FFTdata.maxFrequency = 100; % 对应APP Max frequency for THD computation % FFTdata.
FreeRTOS学习笔记(3、信号量、互斥量的使用) 前言往期学习笔记链接学习工程信号量 semaphore两种信号量的对比信号量的使用1、创建信号量2、give3、take4、删除信号量使用计数型信号量实现同步功能使用二进制型信号量实现互斥功能 互斥量 mutex问题:优先级反转解决方法:优先级继承问题:递归上锁造成死锁解决方法:递归锁互斥量的基本使用1、创建互斥量2、获得互斥量 Take3、释放互斥量 Give 使用优先级继承来实现优先级反转二进制信号量优先级反转的过程分析互斥量使用优先级继承来解决优先级反转 互斥量和二进制信号量的区别和共同点互斥量的递归锁递归锁实现1、创建递归锁2、Give/Take 前言 这是第三弹,由于CSDN长度的限制,所以把FreeRTOS学习分为几部分来发,这是第三部分
主要包括信号量、互斥量使用等
往期学习笔记链接 第一弹:FreeRTOS学习笔记(1、FreeRTOS初识、任务的创建以及任务状态理论、调度算法等)
第二弹: FreeRTOS学习笔记(2、同步与互斥通信、队列、队列集的使用)
第三弹: FreeRTOS学习笔记(3、信号量、互斥量的使用)
第四弹: FreeRTOS学习笔记(4、事件组、任务通知)
第五弹: FreeRTOS学习笔记(5、定时器、中断管理、调试与优化)
学习工程 所有学习工程
oufen / FreeRTOS学习
都在我的Gitee工程当中,大家可以参考学习
信号量 semaphore 队列可以传送数据,队列可以传送不同的数据
有的时候只需要传递状态,并不需要传递具体的信息
这就是信号量,不去传送数据,而是传送状态,这样至起到了通知的作用,更加节省内存
信号量,不能传输数据,只有一个计数值,来表示资源的数量
信号起通知作用
量,表示资源的数量
左边是生产者,生产好一个商品后让计数值+1
右边是消费者,取出一个商品后计数值-1
如何创建信号量
创建信号量生产者生产好后让计数值+1 give消费者取出后让计数值-1 take 计数:事件产生give信号量,计数值加1,处理事件,take信号量,计数值减1
资源管理:想要访问资源时,首先需要take信号量,计数值减1,用完资源后,give信号量,计数值加1
两种信号量的对比 计数型信号量二进制信号量 计数型信号量,的取值范围为0-任意数
二进制信号量,的取值返回为0或者1 但是二进制信号量的初始值为0
除了取值不一样外,其他的操作都是完全一样的
信号量也相当于是一个队列
队列有一个结构体Queue,结构体中有一个指针,指向存放数据的一个buff
但是对于信号量,并不需要这个buffer,只需要这个结构体
对于信号量,核心是信号量的计数值
这个计数值保存在初始化信号量时传入的初始的计数值
创建完信号量后,就可以加减信号量的Value了
让信号量的计数值+1,并且取出东西
一开始Value为0,调用take函数,使信号量减1,没有数据,那么信号量就没办法-1,进入阻塞状态,还可以指定阻塞多长时间
在阻塞状态中,如果有另一个task往里面放数据,那么就会从阻塞状态中唤醒,进入Ready状态
对于give,信号量加1 解锁 对于计数型信号量,可以让这个值累加,但是不能超过创建时指定的最大值
对于二进制信号量,取值就只有0和1,如果值为1,再次调用give也不会成功
可以判断give函数的返回值,看累加是否成功
不管哪种信号量,只要没有超过创建时指定的最大值,都可以累加成功
对于take,信号量-1 上锁 如果信号量的值为0,就没办法take成功,不成功的话可以指定阻塞时间
0 take不成功,返回errportMax_Delay 一直阻塞,直到成功 有多个task执行take,当其他task执行give时,唤醒哪个任务? 优先级最高的task 优先执行take**优先级相同时,等待最久的task ** 优先执行take pdTRUE,表示Take成功
FreeRTOS学习笔记(4、事件组、任务通知) 前言往期学习笔记链接学习工程事件组 event groupkeil里面的代码标准事件组的基本使用1、创建事件组2、设置事件3、等待事件 事件组的使用-同步点1、创建事件组2、等待同步 任务通知 task notification任务通知的基础知识任务通知状态的取值任务通知的两类函数任务通知的优缺点 任务通知的使用-轻量级信号量信号量和使用任务通知实现信号量的辨析信号量任务通知实现信号量 1/通知其他任务2/等待任务通知两者区别 任务通知的使用-轻量级队列队列和任务通知实现队列的区别1、队列2、任务通知3、区别 队列实现任务通知实现1、通知值不覆盖2、通知值覆盖 任务通知的使用-轻量级事件组事件组和任务通知实现事件组事件组任务通知实现事件组 事件组实现任务通知实现事件组 前言 这是第四弹,由于CSDN长度的限制,所以把FreeRTOS学习分为几部分来发,这是第四部分
主要包括事件组、任务通知等
往期学习笔记链接 第一弹:FreeRTOS学习笔记(1、FreeRTOS初识、任务的创建以及任务状态理论、调度算法等)
第二弹: FreeRTOS学习笔记(2、同步与互斥通信、队列、队列集的使用)
第三弹: FreeRTOS学习笔记(3、信号量、互斥量的使用)
第四弹: FreeRTOS学习笔记(4、事件组、任务通知)
第五弹: FreeRTOS学习笔记(5、定时器、中断管理、调试与优化)
学习工程 所有学习工程
oufen / FreeRTOS学习
都在我的Gitee工程当中,大家可以参考学习
事件组 event group 可以通过队列传送数据
可以通过信号量,来传递状态信息
还可以使用互斥量来实现临界资源的互斥访问(独占)
但是上述都没办法解决事件组,事件组包含多个事件
事件组,右边可以等
若干个事件中的某个事件某个事件若干个事件中的所有事件 从学习此知识点开始,使用Source Ingsight编辑代码,不再使用VScode
事件组的创建函数
事件组的结构体
EventBits_t 代表一个整数,每一位bit代表一件事件
当生产者,生产完后就可以设置这个EventGroup的某一位,表示这个事件我做完了
生产者1和生产者2所做的事情不一样,所设置的位也不一样
如果事件组里没有东西,那么消费者任务就会等待
这些任务存放在List_t xTasksWaitingForBits;链表中
使用事件组
创建事件组 左边生产者set bits 设置事件的某个位 能够设置哪个事件,就去设置哪个位
右边消费者 wait bits 等待事件的某个位 同步点 假如有taskA、taskB、taskC
taskA做完某些事情后,设置bit0,等待三个任务的bit都设置为1后才可以做下一步
taskB同
taskC同
这三个task都可以调用这个函数表示完成了某件事情
FreeRTOS学习笔记(5、定时器、中断管理、调试与优化) 前言往期学习笔记链接学习工程定时器定时器的三要素守护任务定时器的状态定时器的基本使用1、创建定时器并书写中断回调函数2、开启定时器 定时器消除抖动普通的外部中断定时器防抖 中断管理两套API函数的区别xHigherPriorityTaskWoken 参数使用`portEND_SWITCHING_ISR` 宏来切换任务定时器在ISR中的使用 资源管理如何访问临界资源1、任务访问临界资源2、任务和中断访问临界资源 禁止任务调度如何屏蔽中断 调试和优化调试1、打印(printf)2、断言3、Trace4、回调函数 HookMalloc Hook函数栈溢出Hook函数 优化栈的使用情况 CPU的运行时间获取任务统计信息、CPU的占用率等1、开启定时器中断2、配置宏3、获取任务统计信息 or CPU占用率 前言 这是第五弹,由于CSDN长度的限制,所以把FreeRTOS学习分为几部分来发,这是第五部分
主要包括定时器、中断管理、调试和优化等
往期学习笔记链接 第一弹:FreeRTOS学习笔记(1、FreeRTOS初识、任务的创建以及任务状态理论、调度算法等)
第二弹: FreeRTOS学习笔记(2、同步与互斥通信、队列、队列集的使用)
第三弹: FreeRTOS学习笔记(3、信号量、互斥量的使用)
第四弹: FreeRTOS学习笔记(4、事件组、任务通知)
第五弹: FreeRTOS学习笔记(5、定时器、中断管理、调试与优化)
学习工程 所有学习工程
oufen / FreeRTOS学习
都在我的Gitee工程当中,大家可以参考学习
定时器 闹钟什么时候响,闹钟响了之后要做什么事情,这个闹钟是一次性的还是周期性的
定时器的三要素 超时时间(定时器周期)回调函数单次触发还是周期性的触发 守护任务 守护任务的作用 处理命令,从命令队列中取出命令、处理执行定时器的回调函数 能否及时执行定时器中断回调函数,严重依赖于守护任务的优先级
创建定时器后,然后启动定时器
启动定时器,实质上是向队列中写入命令数据,第二个参数就是等待时间,如果队列满的话,就无法写入队列,阻塞等待
启动定时器时,会记录启动定时器的当前tick,此时的tick是初始时间,当定时器过了定时时间后,即当前时间tick>=初始tick+定时时间时,就会触发Timer
对于一次性的定时器,将会触发一次
对于周期性的定时器,将会周期性的触发
定时器回调函数应该尽快执行完,如果执行时间过长,将会阻碍其他定时器函数的执行
在定时器中断回调函数中不要使用delay,不能进入阻塞状态
可以调用在任务中使用的函数,但是等待事件要设置为0,即刻返回,不可以阻塞
否则将会影响其他任务的执行,一直堵塞在定时器中断回调函数中
触发指的是回调函数被调用,被谁调用呢?
tick中断中去调用回调函数 (在Linux中调用)在FreeRTOS中,只能在某个任务中执行 tick中断,每定时1次,就会判断一下,有没有超时的定时器,如果有的话将会唤醒这个任务,调用回调函数,这个任务被称为守护任务
守护任务的函数
当tick中断把守护任务唤醒之后,如果他的优先级比较高的话,最高的话就可以执行定时器的回调函数
如果优先级比较低,就会被更高优先级任务抢占,那么定时器中断回调函数就无法执行,从而阻塞
守护任务的三个宏定义,一旦使用定时器就需要定义这三个宏,分别表示守护任务的优先级、队列长度、任务分配栈的大小
守护任务执行Timer回调函数,如果其他任务想要设置Timer,只能通过队列发消息给守护任务(比如启动定时器)
用户使用定时器时,实质都是把某些命令都发送到定时器命令队列里
把数据存入队列,对方任务就会被唤醒,就会从队列里取出命令,从而修改定时器的值
写入队列,都会有等待时间
定时器的状态 定时器中有两个状态
Dormant状态 (休眠状态)Running状态 (运行状态) 当创建定时器时,这个定时器处于Dormant状态,定时器并未运行,我们可以修改定时器的,启动/复位/修改周期
很久以前,我们发布过一个单细胞多组差异基因可视化的方法。跟着Cell学单细胞转录组分析(八):单细胞转录组差异基因分析及多组结果可视化。主要复现参考的是这篇发表在《Cell》上的文章。可以将多个组的差异结果展示出来。
(reference:A Spatiotemporal Organ-Wide Gene Expression and Cell Atlas of the Developing Human Heart)
这里我们对之前的帖子进行更新,主要是解决之前的一些问题,让作图更加清晰正确。此外,我们直接将差异基因的分析和可视化包装成一个通用的函数,函数有一定的可调节性。
函数解释如下:
函数的使用视频见B站:
https://www.bilibili.com/video/BV19w411D7qZ/?spm_id_from=333.999.0.0
接下来我们测试一下:这里差异基因的分析使用的是Seurat的Findmarkers函数,所以一些参数和Findmarkers是一样的,自行调节。最好可以将logfc.threshold和min.pct设置为0,这样就可以获得所有的基因,这个结果我们函数是直接保存在相关路径中的,那么这么做有什么用呢?这个结果可以进行富集分析,更重要的是可以进行GSEA分析(复现Nature图表:GSEA分析及可视化包装函数、(视频教程)GSEA分析可视化函数/棒棒糖图展示富集结果)。
KS_scRNA_multiVlnvo_plot(Seurat_object = uterus, DEGs_outdir = "./", DEGs_list=F, min.pct = 0.3, logfc.threshold = 0.3, test.use = "wilcox", group = "orig.ident", ident.1 = "EEC", ident.2 = "HC", logFC_cut = 0.3, top_gene=T, text_size = 3, height = 0.3) 很显然,由于不知道差异结果如何,所以上面的图参数没有调整,不是很好,我们需要进行细节调整。可是如果是这样的话,难道又要跑一遍差异基因分析吗?显然是很麻烦的,我们可考虑到这个问题。还记得上一步我们差异基因结果已经保存了吗,接下来只需要作图的话dges参数设置为刚才保存的差异结果,DEGs_list设置为T。
KS_scRNA_multiVlnvo_plot(Seurat_object = uterus, DEGs_list=T, dges = sce_DEGs, logFC_cut = 0.3, top_gene=T, text_size = 3, height = 0.
之前微信VIP群小伙伴问道一个图的做法,是一篇《cell reports》上的文章,展示marker基因的表达的时候,添加上了等高线密度图,之前我们提到过单细胞作图在上面添加等高线(参考:单细胞marker基因可视化的补充---密度图与等高线图)。但是小伙伴发现这个图只有表达的细胞上面添加了等高线密度。所以这里我们修改一下,其实很简单,只需要调整密度的表达量阈值即可。
(reference:Dissecting Cell Lineage Specification and Sex Fate Determination in Gonadal Somatic Cells Using Single-Cell Transcriptomics)
原文作者有很多的函数上传到github,自行下载原文查看,还是有很多好代码的,但是它的代码并不能满足我们复杂的作图。而且数据完全不一样。不过它图的修饰和颜色可以参考。所以这里我们重新写了一个作图函数,可以展示UMAP、TSNE降维的单细胞seurat对象单个或者多个marker基因的展示。完整版注释函数和示例数据已上传群文件,自行下载!
接下来我们看看具体的效果。
演示视频参见B站:
https://www.bilibili.com/video/BV1YF41117Py/?spm_id_from=333.999.0.0&vd_source=05b5479545ba945a8f5d7b2e7160ea34
首先做一下TSNE降维的单个marker展示:
#TSNE降维单个基因KS_plot_density(obj=uterus, marker= "CCL5", dim = "TSNE", size =1) 然后是多个marker的展示:增加ncol参数。设置组图的列数。
#TSNE降维单多个基因KS_plot_density(obj=uterus, marker=c("ACTA2", "RGS5","CCL5", "STK17B"), dim = "TSNE", size =1, ncol = 2) 最后看一下UMAP降维的数据:
#UMAP降维marker基因展示KS_plot_density(obj=human_data, marker=c("CD3E", "S100A2"), dim = "UMAP", size =1, ncol =2) 具体函数如下:
KS_plot_density <- function(obj,#单细胞seurat对象 marker,#需要展示的marker基因 dim=c("TSNE","UMAP"), size,#点的大小 ncol=NULL#多个marker基因表达图排序 ){ require(ggplot2) require(ggrastr) require(Seurat) cold <- colorRampPalette(c('#f7fcf0','#41b6c4','#253494')) warm <- colorRampPalette(c('#ffffb2','#fecc5c','#e31a1c')) mypalette <- c(rev(cold(11)), warm(10)) if(dim=="
https://qa.fmod.com/t/skip-seek-to-specific-time-within-sound/15766
FMOD.Studio.EventInstance instance; int aa = 0; public void SetTimelinePosition(int milliSeconds) { string Event = "event:/Music/War_on_top/Music"; if (aa == 0) { aa = 1; FMOD.Studio.EventDescription eventDescription = RuntimeManager.GetEventDescription(Event); eventDescription.createInstance(out instance); FMOD.RESULT result = instance.setTimelinePosition(milliSeconds); instance.start(); } else { FMOD.RESULT result = instance.setTimelinePosition(milliSeconds); } } public int GetTimelinePosition() { instance.stop(FMOD.Studio.STOP_MODE.IMMEDIATE); aa = 0; return 0; } void SetTimelinePosition(int milliSeconds); int GetTimelinePosition(); public void GetTimelinePosition() { if (m_testFmod == null) { m_testFmod = EngineUtility.
C++中结构体(struct) 我们知道C++中的 struct 对C中的 struct 进行了扩充,它不再是只能用来封装不同类型数据的数据结构了,而是拥有了更多的功能,例如:可以包含成员函数,可以继承,可以实现多态!!,这些功能与C++中的类很相似。
那么接下来我们解剖一下C++中结构体struct与类class的区别。
C++中struct与class的区别 一、class和struct 本身成员的默认访问级别不同 这是最本质的区别,结构体的成员和成员函数在默认情况下的访问级别是公有的(public),类的成员和成员函数在默认情况下的访问级别是私有的(private)。
注意: 二者的访问方式都是 对象名+点(对象成员选择运算符)+访问对象成员
不用多介绍,我们直接通过下面的代码进行区分和理解:
struct的用法:不加任何访问限定符,struct默认访问权限是public,即成员可直接在结构体外被访用。其他用法与class类似,即对象定义时struct类型也可省略。 #include <iostream> using namespace std; struct Student{ public: int Age ; char Name[16]; }; struct Student1{ int Age =22 ; char Name[16] = "李四"; }; int main() { struct Student stu = { 18,"张三" }; //struct初始化 cout<< stu.Name <<" " <<stu.Age<< endl; struct Student1 s ; cout<< s.Name <<" " <<s.Age<<endl; s.Age = 55; cout<< "
一运行项目,发现页面没数据,看微信开发者工具报错了,连接不上、访问不通。
1.首先看一下ip地址是不是本机的。
命令提示符输入ipconfig,看一下IPv4 地址和项目中的请求地址Url是否一致。
2.电脑搜索“服务”,找到对应的数据库服务,启动数据库服务。
4.顺便看看后端有没有启动,命令提示符界面切换在项目后端的文件夹下,输入npm start回车。
5.停止运行前端项目,重新启动一下。
一 、四大组件官网指南 1.Activity
https://developer.android.google.cn/guide/components/activities/intro-activities?hl=zh-cn
https://developer.android.google.cn/guide/topics/ui/shortcuts/creating-shortcuts?hl=zh-cn
https://developer.android.google.cn/guide/fragments?hl=zh-cn
https://developer.android.google.cn/guide/components/intents-filters?hl=zh-cn
2.service https://developer.android.google.cn/guide/components/services?hl=zh-cn
3.broadcast https://developer.android.google.cn/guide/components/broadcasts?hl=zh_cn
4.ContentProvider https://developer.android.google.cn/guide/topics/providers/content-providers?hl=zh_cn
二、 Activity 1.1 Activity页面启动 1.1.1 Activity的启动和结束 通过startActivity方法可以从当前页面跳到新页面,具体格式如“startActivity(new Intent(源页面.this, 目标页面.class));”。譬如以下代码便在重写后的点击方法onClick中执行页面跳转动作。
// 活动类直接实现点击监听器的接口View.OnClickListener public class ActStartActivity extends AppCompatActivity implements View.OnClickListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_act_start); // setOnClickListener来自于View,故而允许直接给View对象注册点击监听器 findViewById(R.id.btn_act_next).setOnClickListener(this); } @Override public void onClick(View v) { // 点击事件的处理方法 if (v.getId() == R.id.btn_act_next) { // 从当前页面跳到指定的新页面 //startActivity(new Intent(ActStartActivity.this, ActFinishActivity.class)); startActivity(new Intent(this, ActFinishActivity.class)); } } } 在Java代码中,调用finish方法即可关闭当前页面。比如要求点击箭头图标或完成按钮都返回上一页面,则需给箭头图标和完成按钮分别注册点击监听器,然后在onClick方法中调用finish方法。下面便是添加了finish方法的新页面代码例子:
----------------------利用技术实现规模的框架(Vince Iswara)-------------------
概述:
----------------挑战1:最大限度的发挥有限资源的影响
搭建一个框架,找到框架中的优先级,同时找到框架中的焦点,
框架:
当我们看到一个问题,我们应该知道:
它是什么(以便于知道能够取得的最低的果实)
我们开头可以做什么,(以便于我们可以知道即刻的影响和结果)或者一开始反思做什么有最大的影响
优先级:最低成果,最大影响,客户定位,客户需求,最广泛的地址市场,与其他同类型的产品相比更有优势的地方在哪里
----------------挑战2:与公司一起扩展团队
1.believe 2.理解 3.确定领导人,有冲突的时候怎样协调 4.成员间相互学习 5.商友关系:是你通向其他领域的路径 6.团队文化:团队建立的信念,团队的价值(每个人的价值),这可以让我们在解决问题的时候更明确
-------------挑战3:扩展过程中的优先级和管理
为什么要这样做>抛出一个目的
让团队有信念去做任何一件事
建立一个让自己能够做出正确决断的结构(多总结)
---------------对构建做出什么明智决定
可以采用的方法:市场调查,小组讨论,自己假设
以上这些方法想到的的有益的东西可以进行总结并且选出最好的
------------随着客户获取、保留和关怀而扩展
CAC:客户获取成本(用多少钱能把你和你的客户之间联通起来)
所有存在CAC的事情才会真正的让你和·别人建立关系,【加入你的CAC成本为0,比如去电影院看电影 改为 下载到手机上面看 那么这件事情有很大概率会被忘掉 因此,建立联系其实是很困难的】
客户关怀的重要性。
------------使用系统和自动化进行扩展
API:程序间的接口
RPA:机器人加工自动化
使用系统和自动化进行扩展可以让我们更快的扩展业务。
-----------案例研究:肯德基
KFC:第一个离线支付用例
支付方式的进步让我们不用排队,加快了时间
-----------敏捷开发
关于敏捷开发的认知:通俗易懂的理解敏捷开发是什么——认知篇 - 知乎 (zhihu.com)
------------------案例研究:bukalapak(布卡拉帕克) -------------测试和优化
测试指标:KPI【 KPI可以使部门主管明确部门主要责任,并进一步明确部门人员各自的业绩指标。】
优化方法:检查目标是否明确,不明确就更换
------------------案例研究(能学到的东西):苹果 1.有一个明确的目标
2.当不能达到目标时,学会快速的移动调整
3.学会合作
--------------------创新文化:支持您的团队
-------------------尽量不要犯错,如果错了,请从中吸取教训
---------------创新的基础:了解您的客户
NPS:可以简单理解为评估 产品口碑 的指标。
NPS分数=(推荐者人数-批评者人数)/总人数
--------------案例研究:点对点汇款
降低了客户的维护成本
-------------------利用技术解决用户痛点的框架---------------
(lgnatius Ong(Former CEO, Touch 'n Go eWallet))
1、前言 考虑下面几个条件下如何提升kafka的消费速度
消息要求严格有序,如chat聊天消息业务处理速度慢,如处理一条数据需要100ms分片不合理,如有的分区很闲,有的分区消息数量积压 2、解决方案 1、顺序问题 关于消息消费时存在先后顺序问题,在chat聊天系统消息消费时遇到的问题及优化思路(一)中已经加以说明。具体实现大致为对同一会话、帖子Id等维度放入同一分区中,如使用Id % 分区数,如下图:
上面的解决方案是将同一会话的消息发送至同一分区进行消费,但是但消费者的消费能力大概率是不够的,因此,需要并发处理,详见
chat聊天系统消息消费时遇到的问题及优化思路(一)
注意:此时需要注意一个问题就是,当单个消费者消费分区,并将获取到的消息放入不同的队列中,此时还可能存在乱序问题,所以,可以考虑复用Id%队列数的方式,将同一个会话的消息放入到相同的队列中,让协程进行消费。
2、消息不丢失问题 上面的方案,当消费者从kafka拉到消息后,并没有等待处理完成就继续从kafka拉取消息然后缓存到内存中,等待消费队列慢慢消费,这个时候如果机器宕机,则内存中的消息将会丢失。
基于上面描述的问题,考虑使用手动提交offset。但是这样其实还存在一个问题就是:各个协程处理的offset值其实是不一样的,如下图:
此时goroutine1和goroutine2 的消息的offset不一致,为了保证消息不丢失,采用以下策略:定期手动提交当前的offset信息,提交的offset值选当前分区的最小的offset,如上面的就选1001这个offset值。可以采用在内存中缓存处理的offset列表的实现方式,如下:
当内存中待处理的最大offset与最小的offset差值>= M时,阻塞消费线程继续从kafka拉取消息,控制异常情况下的数据最多不多于M条
但是此时会引进一个新问题:消息重复消费
此时要保证消息消费的幂等性,如可通过消息唯一标识放入如redis中判断
3、消息堆积问题 堆积原因:
生产者短时间生产大量消息到broker,消费者无法及时消费,如大促生产者无法感知消息堆积,仍继续生产消息,导致消息堆积进一步加剧消费者能力不足,消费时间长,消费者宕机、网络异常与broker无法通信业务功能存在bug,导致消费者无法消费 解决方案
消费者端
增加消费者数量,并采用并发消费提高消费速度,避免消费时间过长。如果单条消息消费时间无法优化,可以提高批次拉取的数量(当批次拉取的数量较少时,拉取数据量/处理时间 < 生产速度时就容易堆积)消费消息时尽量减少耗时操作,尽量减少三方接口调用、读写库等合理设置消费组服务数量,合理增加topic的partition=个数,消费者数 >= 分区数补偿消费,即消费跳过积压数据,直接消费最新的数据,同时启动补偿数据进程消费积压数据 生产者端
支持熔断与隔离,当broker消息积压时,对生产者熔断根据key采用合适的算法,将消息均匀分不到对应的分区中 服务端
进行预估,设置合理的分区数 在电商中经常大促,因此很容易出现短时间内产生大量消息的问题,因此在大促前可根据历史情况进行容量预估和相关的扩容策略。
参考: 我是如何将一个老系统的Kafka消费者服务的性能提升近百倍的
文章目录 前言一、校招二、时间复杂度1、单层循环2、双层循环 三、空间复杂度四、数据结构五、校招算法题实在不会做,有没有关系?六、英雄算法集训 前言 英雄算法联盟八月集训 已经接近尾声,九月算法集训将于 09月01日 正式开始,目前已经提前开启报名,报名方式见 这里,想要参加的建议提早报名,因为对于算法零基础的同学会有一些提前的准备工作,比如需要1 - 3天的时间完成预训练 和 九日集训 提前养成刷题的习惯,再参加算法集训会更加有成效。
一、校招 对于校招,很多同学最惧怕的莫过于算法题了,因为很多题目,虽然感觉似曾相识,但是题型千变万化,加上紧张的氛围,原本会做的算法也不会了,从而和这次招聘失之交臂。
那么算法在平时工作中,到底起多大的作用?是否一定要学呢?这个应该是绝大多数同学最困惑的问题,看完这篇文章,你的心中或许会有一定的答案。
二、时间复杂度 但凡写过代码的同学都知道,如果一段代码执行效率低,那么在函数层层嵌套下,整个函数执行完的时间就会变长,就有可能出现未响应的情况。
如果一个软件,每一步操作都非常耗时,给人的体验就是非常卡,那么这款软件最终的归宿就是走向灭亡,所以 执行效率 对于编程来说是至关重要的,而这里的执行效率就对应的算法的时间复杂度。
1、单层循环 所谓穷举法,就是我们通常所说的枚举,就是把所有情况都遍历了(跑到)的意思。举个最简单的例子:
【例题1】给定 n ( n ≤ 1000 ) n(n \le 1000) n(n≤1000) 个元素 a i a_i ai,求其中 奇数 有多少个。
判断一个数是偶数还是奇数,只需要求它除上 2 的余数是 0 还是 1,那么我们把所有数都判断一遍,并且对符合条件的情况进行计数,最后返回这个计数器就是答案,这里需要遍历所有的数,这就是穷举。如图所示:
c/c++ 代码实现如下:
int countOdd(int n, int a[]) { int cnt = 0; for(int i = 0; i < n; ++i) { if(a[i] & 1) ++cnt; } return cnt; } 其中a & 1等价于a % 2,代码a模 2 的余数;而这个算法的时间复杂度就是 O ( n ) O(n) O(n)。
hexview下载路径:https://download.csdn.net/download/kxajd001/88261758
set year=%date:~0,4% set month=%date:~5,2% set day=%date:~8,2% SET hour=%time:~0,2% IF "%hour:~0,1%"==" " SET hour=0%HOUR:~1,1% SET minute=%time:~3,2% set path=.\..\..\01_SrcCode\app\project_20%date:~2,2%%month%%day%_%hour%%minute% echo path =%path% mkdir %path% mkdir %path%\JFlash mkdir %path%\JFlash\ETC\JFlash mkdir %path%\mcuboot mkdir %path%\mcuApp copy .\..\..\boot\Debug\Exe\boot.hex %path%\mcuboot\boot.hex /v copy .\..\..\01_SrcCode\app\Debug\Exe\app.hex %path%\mcuApp\app.hex /v copy .\..\..\01_SrcCode\app\tool %path%\JFlash\ /v copy .\..\..\01_SrcCode\app\tool\ETC\JFlash %path%\JFlash\ETC\JFlash /v Rem Path to the executable exe of the Vector HexView tool on your PC set "HexViewPath= .\..\..\tool\HexView\hexview.exe" Rem Input_hex_File1 indicates one of the merged source files and its path set "
docker中执行playwright install 报错:OSError: /lib64/libm.so.6: version `GLIBC_2.27' not found
下载GLIBC_2.27版本:Index of /gnu/libc
安装:
1、tar -zxvf glibc-2.29.tar.gz
2、cd glibc-2.29
3、mkdir build
4、cd build/
5、../configure --prefix=/usr/local --disable-sanity-checks
执行第5步时,又报错:
根据网上解决办法执行下列命令:
sudo apt install gawk
sudo apt install bison
但是...执行时又报错.....忘记截图...后面截不到了(报错:The following signatures couldn't be verified because the public key is not available)
最终网上搜了半天,都没结果,无意间看到需要清理磁盘空间..
我就把虚拟机的内存从默认20G设置到40G设置,运行内存从2g设置到4g,再次启动,
再次执行
sudo apt install gawk
sudo apt install bison
可以成功。。。然后再往上推。。。。