欢迎回到今天的 Python 课堂。
老样子,咱们先复习复习上一节的内容。
在上一节课中,我们重点学习了列表的概念,以及如何使用索引、切片和增改操作对列表进行取值和修改。
还学习了类似于列表的元组。元组与列表不同的是,列表用中括号[]表示,而元组则用小括号()表示。
元组和其他数据结构不同之处在于一旦创建,就无法修改。
列表和元组都属于序列这一数据类型,即多个数据以一列的形式排列。
字符串也是序列类型之一,除了列表和元组。
在今天的学习开始之前,我们需要先回顾一下本节可能会涉及到的知识。
单选题: 请你选出以下选项中错误的一项:
A.元组不能被转换成列表
B.列表、字符串、元组都为序列类型
C.列表里的索引是从0开始计数
D.format() 括号中的标识和替换字段的标识要对应
解析:可以使用 list() 函数将元组转换为列表类型
答案:A
代码题: 程序设计:今天我上课比较匆忙,不知道书包里有没有电脑,请设计一个程序帮我判断:
1)如果"电脑"在书包里面,就显示"可以好好上课了";否则显示"赶紧回宿舍拿电脑";
2)已知:书包 bag = [‘电脑’, ‘笔’]
`# 创建列表bag bag = ['电脑', '笔'] # 条件判断:如果'电脑'在列表bag中 # print打印对应语句 # 否则: # print打印对应语句` 答案:
# 创建列表bag bag = ['电脑', '笔'] # 条件判断:如果'电脑'在列表bag中 if '电脑' in bag: # print打印对应语句 print('可以好好上课了') # 否则:``else: # print打印对应语句 print('赶紧回宿舍拿电脑') #接下来,一起来看看本节课的学习内容吧。 在前面的学习中,我们已经知道控制流包括顺序结构、分支结构和循环结构。
你已经很熟悉顺序结构和分支结构了,接下来将重点讲解循环结构。
今天的重难点也是循环控制的语法。
先来了解一下 for 循环语句吧。
应用场景: Python自动化处理Word文档的功能可以应用于许多场景,以下是其中一些常见的应用场景:
批量处理文档:如果您需要处理大量的Word文档,例如替换文本、添加文本、修改格式等,手动完成这些任务将非常耗时和繁琐。使用Python自动化处理Word文档,可以轻松地处理大量文档,提高效率。
数据清洗和分析:在数据分析中,经常需要将数据从不同的来源合并到一个数据集中。如果这些数据来源是Word文档,使用Python自动化处理Word文档可以帮助您更轻松地提取和清洗数据。
帮助文档生成:如果您需要为软件或产品编写帮助文档,使用Python自动化处理Word文档可以帮助您更轻松地生成和更新文档。
合同和法律文件管理:在合同和法律文件管理中,经常需要查找和修改特定的信息,例如公司名称、地址、电话号码等。使用Python自动化处理Word文档可以帮助您更快速地更新和管理这些文档。
总之,Python自动化处理Word文档的功能可以应用于许多场景,帮助人们更轻松地处理和管理文档。无论您是需要处理几个文档还是数百个文档,使用Python自动化处理Word文档都可以帮助您提高效率,并减少手动处理文档所需的时间和精力。
源代码: import os import docx # 遍历docx目录中的所有Word文档 for filename in os.listdir('D:\spiderdocs\docx'): if filename.endswith('.docx'): # 打开Word文档 doc = docx.Document('D:\spiderdocs\docx\{}'.format(filename)) # 遍历文档中的所有段落 for para in doc.paragraphs: # 将“三江源”替换为“雅鲁藏布” para.text = para.text.replace('三江源', '雅鲁藏布') # 遍历文档中的所有表格 for table in doc.tables: # 遍历表格中的所有单元格 for row in table.rows: for cell in row.cells: # 将“三江源”替换为“雅鲁藏布” cell.text = cell.text.replace('三江源', '雅鲁藏布') # 保存修改后的文档 doc.save('D:\spiderdocs\docx\{}'.format(filename)) 源代码说明: 以上代码将遍历D:\spiderdocs\docx目录中的所有Word文档,对于每个文档,它将遍历文档中的所有段落和表格单元格,并将“三江源”替换为“雅鲁藏布”。修改后的文档将保存在原始文档的同一目录中,文件名不变。
请注意,在替换文本时,我们使用了Python字符串的replace方法。这个方法将搜索字符串中的所有匹配项,并用指定的替换字符串替换它们。
效果如下: 环境以及数据和文件准备: 1、安装docx模组:
pip install python-docx 2、创建100个docx并在其中输入文字包含“三江源”:
解决temporary failure resolving mirrors.aliyun.com 环境: 宿主机:win10 虚拟机平台:vmware 17 虚拟机: ubuntu20 问题:安装虚拟机时设置镜像仓库为http://mirrors.aliyun.com/ubuntu 进入虚拟机后执行安装出现:temporary failure resolving mirrors.aliyun.com 排查:确认地址无误后,确定是域名解析器也就是DNS出现问题 解决方案: 修改etc/systemd/目录下的resolved.conf文件也就是下图,然后重启即可 vi /etc/systemd/resolved.conf
Library source does not match the bytecode for class XXX 本人遇到这种错误的情况:SpringBoot能正常启动,但是右上角启动类上有个小红×:
导入自己写的包下的类时报红,然后打开类时报错:
尝试过很多方法之后终于解决了:
1、打开File -> Project Structure
2、点击Libraries,找到自己的项目
然后删除自己的项目的Library,再重新添加就好了。
如果说,你遇到的是查看导入的依赖类时报错,则是因为依赖的版本不对,将该版本的jar包全部删除掉,用maven重新下载就好了。
CLIP原理解读 一. 核心思想 通过自然语言处理来的一些监督信号,可以去训练一个迁移效果很好的视觉模型。
论文的作者团队收集了一个超级大的图像文本配对的数据集,有400 million个图片文本的配对, 模型最大用了ViT-large,提出了CLIP(Contrastive Language-Image Pre-training),是一种从自然语言监督中学习的有效方法。尝试了30个数据集,都能和之前的有监督的模型效果差不多甚至更好。
二. 方法实现 1. CLIP的训练过程 模型的输入是图片和文字的配对,图片输入到图片的encoder得到一些特征,文本输入到文本的encoder得到一些特征,每个traning batch里有n个图片-文本对,就能得到n个图片的特征和n个文本的特征,然后在这些特征上做对比学习,对比学习非常灵活,就需要正样本和负样本的定义,其它都是正常套路(不懂对比学习),配对的图片-文本对就是正样本,描述的是同一个东西,特征矩阵里对角线上的都是正样本,矩阵中非对角线上的元素都是负样本,有了正负样本,模型就可以通过对比学习的方式去训练了,不需要任何手工标注。这种无监督的训练方式,是需要大量的训练数据的。
2. CLIP的推理过程 预训练之后只能得到文本和图片的特征,是没有分类头的,作者提出一种利用自然语言的方法,prompt template。比如对于ImageNet的类别,首先把它变成"A photo of a {object}" 这样一个句子,ImageNet有1000个类,就生成1000个句子,然后这1000个句子通过之前预训练好的文本的encoder能得到1000个文本特征。直接用类别单词去抽取文本特征也可以,但是模型预训练的时候和图片配对的都是句子,推理的时候用单词效果会下降。把需要分类的图片送入图片的encoder得到特征,拿图片的特征和1000个文本特征算余弦相似性,选最相似的那个文本特征对应的句子,从而完成了分类任务。不局限于这1000个类别,任何类别都可以。彻底摆脱了categorical label的限制,训练和推理的时候都不需要提前定义好的标签列表了。
优点:相比其它的训练方法,从自然语言的监督信号来学习,有几个好处。首先,不需要再去标注数据,比如用传统方法做分类,需要先确定类别,然后去下载图片再清洗,再标注,现在只需要去下载图片和文本的配对,数据集很容易就做大了,现在的监督对象是文本,而不是N选1的标签了。其次,训练的时候把图片和文本绑在了一起,学到的特征不再单是视觉特征了,而是多模态的特征,和语言连在一起以后,就很容易做zero-shot的迁移学习了。
3. CLIP的损失函数 有两个输入,一个是图片,一个是文本,图片的维度是[n,h,w,c],文本的维度是[n,l],l是指序列长度,然后送入到各自的encoder提取特征,image encoder可以是ResNet也可以是Vision Transformer,text encoder可以是CBOW,也可以是Text Transformer,得到对应的特征之后,再经过一个投射层(即W_i和W_t),投射层的意义是学习如何从单模态变成多模态,投射完之后再做l2 norm,就得到了最终的用来对比的特征I_e和T_e,现在有n个图像的特征,和n个文本的特征,接下来就是算consine similarity,算的相似度就是最后要分类的logits,最后logits和ground truth做交叉熵loss,正样本是对角线上的元素,logits的维度是[n,n],ground truth label是np.arange(n),算两个loss,一个是image的,一个是text的,最后把两个loss加起来就平均。这个操作在对比学习中是很常见的,都是用的这种对称式的目标函数。
三. 实验 1. 研究动机 在计算机视觉中,zero-shot学习主要指研究对unseen datasets的泛化。之前的那些自监督和无监督的方法,主要研究的是特征学习的能力,目标就是学一种泛化性比较好的特征,但即使学到了很好的特征,想应用到下游任务,还是需要有标签的数据做微调,所以有限制,比如下游任务数据不好收集,可能有distribution shift的问题。怎么做到只训练一个模型,后面不再需要微调了呢,这就是作者研究zero-shot迁移的研究动机。借助文本训练了一个又大又好的模型之后,就可以借助这个文本作为引导,很灵活的做zero-shot的迁移学习。
在clip预训练好之后,就有2个编码器,一个是图像编码器,一个是文本编码器,推理时给定一张图片,通过编码器就能得到一个图片的特征,文本那边的输入就是感兴趣的标签有哪些,比如plane,car,dog等,这些词会通过prompt engineering得到对应的句子,比如‘A photo of a plane’,‘A photo of a dog’,有了这些句子以后,送入到文本编码器,就能得到对应的文本特征,这里假设是plane,car,dog这3个,然后拿这3个文本的特征去和那张图片的特征做余弦相似度,计算得到相似度以后再 通过一个softmax得到概率分布,概率最大的那个句子就是在描述这张照片。
2. 实验结果 作者在27个数据集上做了实验,在16个数据集上的测试指标超越了完全监督学习的方法,体现了zero-shot的泛化性。
Zero-shot CLIP的鲁棒性
四. 论文点评 该论文是2021年Open AI的作品,作者使用4亿图文对进行训练,并将图片特征和文本特征对齐,展现出强大的Zero-shot能力。后续很多大模型或者多模态都可以看到这篇论文的影子,值得精读。
欢迎技术交流!!!
WeChat:guopeiAI
Xgboost Xgboost3.0 原理概述3.0.1 基本思想和特点 3.1 参数概况3.1.0 参数建议3.1.1 Xgboost实现的sklearn接口3.1.2 Xgboost原生库 3.2 objective损失函数3.3 迭代过程参数3.3.1 num_boost_round&eta3.3.2 base_score3.3.3 max_delta_step 3.4 目标函数3.5 三大评估器与DART树(booster)3.6 不纯度衡量指标criterion结构分数3.7 弱评估器的控制参数3.8 控制复杂度(抽样控制)3.9 其他参数3.10 参数总结3.11 结构化分数样例3.12 超参数优化3.12.1 参数影响力3.12.2 参数空间的确定3.12.4 优化代码 3.13 Xgboost数学原理3.13.1 算法流程3.13.2 存在的问题 Xgboost 3.0 原理概述 3.0.1 基本思想和特点 XGBoost中两种非常关键的思想实现的:
第一,实现精确性与复杂度之间的平衡
1. XGBoost为损失函数 L ( y , y ^ ) L(y,\hat{y}) L(y,y^)加入结构风险项,构成目标函数 O ( y , y ^ ) O(y,\hat{y}) O(y,y^)2. 使用全新不纯度衡量指标,将复杂度纳入分枝规则 第二,极大程度地降低模型复杂度、提升模型运行效率,将算法武装成更加适合于大数据的算法
1. 使用估计贪婪算法、平行学习、分位数草图算法等方法构建了适用于大数据的全新建树流程2. 使用感知缓存访问技术与核外计算技术,提升算法在硬件上的运算性能3. 引入Dropout技术,为整体建树流程增加更多随机性、让算法适应更大数据 除此之外,XGBoost还保留了部分与梯度提升树类似的属性,包括:
无论集成算法整体在执行回归/分类/排序任务,弱评估器一定是回归器拟合负梯度,且当损失函数是0.5倍MSE时,拟合残差抽样思想 3.1 参数概况 xgb参数英文文档
问题引入链接
对XGBoost来说,真正难度较大的部分并不是梳理以上算法流程,而是证明这一流程可以让模型向着目标函数最小化的方向运行。在这个流程中包括如下很明显的问题:
建树时拟合的 r i k = − g i k h i k r_{ik} = -\frac{g_{ik}}{h_{ik}} rik=−hikgik究竟是什么?拟合它有什么意义?
结构分数和结构分数增益的公式是如何推导出来的?为什么这样建树可以提升模型的效果?
为什么叶子节点的输出值 w j w_j wj是 − ( ∑ i ∈ j g i k ) ∑ i ∈ j h i k + λ -\frac{(\sum_{i \in j} g_{ik})}{\sum_{i \in j} h_{ik} + \lambda} −∑i∈jhik+λ(∑i∈jgik)?这样输出有什么意义?
课程的第一部分说XGBoost拟合的也是残差,残差在哪里?
定义目标函数与目标函数的自变量 首先,根据之前对目标函数的定义,XGBoost中目标函数是针对一棵树的目标函数,而不是针对一个样本或一整个算法的目标函数。并且,任意树的目标函数都包括三大部分:损失函数 l l l、叶子数量 T T T以及正则项。具体地来说:
假设单一树 f k f_k fk的目标函数为 O k O_k Ok,总共有 T T T片叶子,该树上任意样本 i i i的损失函数为 l ( ( y i , H ( x i ) ) l((y_i,H(x_i)) l((yi,H(xi)),其中 H ( x i ) H(x_i) H(xi)是 i i i号样本在集成算法上的预测结果。树上总共有M个样本,目标函数中使用L2正则化( λ \lambda λ不为0, α \alpha α为0),并且 γ \gamma γ不为0,则该树的目标函数为:
GBDT 2 GBDT2.0 参数概述和迭代过程特点参数概述迭代过程 2.1 init2.1.1 model2.1.2 zero2.1.3 None(sklearn默认)2.1.4 测试 2.2 loss2.2.1 分类loss2.2.2 回归loss2.2.3 回归损失的选择2.2.4 探究离群值对不同的loss的影响 2.3 criterion&min_impurity_decrease2.3.1 criterion(friedman_mse)2.3.2 min_impurity_decrease 2.4 n_estimators&learning_rate2.5 warm_start2.5.1 增量学习2.5.2 确定巨量csv文件中样本条数2.5.3 增量学习过程 2.6 GBDT回归树实现分类的方式2.6.1 二分类模型2.6.2 多分类问题 2.7 提前停止机制2.8 梯度提升树的袋外数据2.9 接口(属性)2.9.1 所有接口2.9.2 接口estimators_体现出来的问题 2.10 和其他集成算法对比的效果2.11 贝叶斯优化2.11.1 参数影响力2.11.2 参数空间范围2.11.3 贝叶斯优化模型2.11.4 进一步调参建议 2.12 手动调参代码2.12.1 boosting算法调参思想2.12.2 调参过程代码 2.13 GBDT的数学原理 2 GBDT 2.0 参数概述和迭代过程 特点 和Xgboost相似都是通过弱评估器对于残差进行拟合:依据上一个弱评估器 f ( x ) t − 1 f(x)_{t-1} f(x)t−1 的结果,计算损失函数 L ( x , y ) L(x, y) L(x,y) , 并使用 L ( x , y ) L(x, y) L(x,y) 自适应地影响下一个弱评估器 f ( x ) t f(x)_{t} f(x)t 的构建集成模型输出的结果,受到整体所有弱评估器 f ( x ) 0 ∼ f ( x ) T f(x)_{0} \sim f(x)_{T} f(x)0∼f(x)T 的影响。GBDT基学习器都是回归模型GBDT以向前阶段的方式构建一个加法模型,它允许优化任意可微损失函数,损失函数有较多的选择。在GBDT算法实现时使用了随机森林的思想(subsample),在创建新的拟合树模型时,可以允许通过随机抽取部分样本数据和特征进行树的构建,增大了软评估器之间的独立性(因此存在了袋外数据)。当弱评估器表现在数据上不稳定时可以通过该方法增加稳定性。但是不适用于样本数据较小的情况。 参数概述 参数简介
😄😄个人介绍
光子郎.进行开发工作七年以上,目前涉及全栈领域并进行开发。会经常跟小伙伴分享前沿技术知识,java后台、web前端、移动端(Android,uniapp,小程序)相关的知识以及经验体会,不定期会有源码及框架的分享,如果你有相关的知识想要及时了解或者讨论,那么请关注光子郎.,点点文末小卡片,不定期会有免费的资源分享给大家,感谢支持~
🍉🍉人生格言
你要批评指点四周风景,首先你要爬上屋顶。
🌈🌈光子郎今天带大家详细的了解Android中的Handler机制,一篇就懂!废话少说,开整!
目录
一、引言
二、Handler机制概述
1.Handler、Message和Looper的基本概念
三、源码结构
1.Handler的源码结构:
2.Message的源码结构
3.Lopper的源码结构
4.关系和协作机制:
四、Handler的使用方法
1.创建Handler对象:
2.发送消息:
3.处理消息:
4.在特定线程中创建Handler对象:
五、Handler的线程安全性
1.创建Handler的正确方式:
2.处理消息的线程安全性:
3.确保消息的处理在正确的线程中执行:
六、Handler进阶操作
1.异步加载数据:
2.延时操作:
3.UI线程更新:
一、引言 在Android开发中,消息传递和线程通信是常见的需求。而Android的Handler机制就是用来实现这种消息传递和线程通信的重要组件。它在Android应用开发中扮演着至关重要的角色。
Handler重要性:
线程间通信:Android应用通常会涉及到多个线程的并发执行,而Handler机制提供了一种简单而高效的方式来实现线程间的通信。通过Handler,我们可以将消息发送到目标线程的消息队列中,并在目标线程中处理消息,从而实现线程间的通信和协作。
异步消息处理:在Android开发中,许多任务需要在后台线程中执行,而将结果更新到UI界面上。Handler机制允许我们在后台线程中处理任务,并通过Handler将结果发送到UI线程,以便更新UI界面。这种异步消息处理的机制在保持UI的响应性和避免阻塞主线程方面起到了至关重要的作用。
定时任务处理:Handler机制还可以用于处理定时任务。我们可以使用Handler的postDelayed()方法来延迟执行代码块或发送延时消息。这对于实现定时刷新、定时执行任务等场景非常有用。
Handler应用场景:
UI更新:当后台任务完成时,通过Handler机制将结果发送到UI线程,以更新UI界面,如显示加载完成的数据、更新进度条等。
后台任务处理:通过Handler机制,可以将后台任务发送到子线程执行,避免阻塞主线程,从而保持UI的流畅性,如网络请求、文件读写等。
定时任务:使用Handler的定时任务功能,可以实现定时执行代码块或发送延时消息,如定时刷新、定时通知等。
线程间通信:通过Handler机制,在不同线程间发送消息和处理消息,实现线程间的通信和协作,如主线程和后台线程之间的通信。
二、Handler机制概述 1.Handler、Message和Looper的基本概念 Handler:
Handler是Android中的消息处理器,它负责接收和处理消息。每个Handler实例都关联一个特定的线程,并与该线程的消息队列相关联。通过Handler,我们可以发送和处理消息,实现线程间的通信和协作。
Message:
Message是Handler传递的消息对象,用于在不同线程之间传递数据。它包含了要传递的数据和附加信息,如消息类型、标志等。Message对象可以通过Handler的sendMessage()方法发送到目标线程的消息队列中,并在目标线程中被处理。
Looper:
Looper是一个消息循环器,它用于管理线程的消息队列。每个线程只能有一个Looper对象,它负责循环读取消息队列中的消息,并将消息传递给对应的Handler进行处理。Looper的工作方式是不断从消息队列中取出消息,并通过Handler的dispatchMessage()方法将消息分发给目标Handler进行处理。
工作原理:
当一个线程需要使用Handler来处理消息时,首先需要创建一个Looper对象,并调用其prepare()方法创建一个与当前线程关联的消息队列。接着,通过Looper的loop()方法启动消息循环,开始循环读取消息队列中的消息。当有消息通过Handler的sendMessage()方法发送到消息队列时,Looper会不断从消息队列中取出消息,并将其传递给对应的Handler进行处理。Handler在接收到消息后,会调用自己的handleMessage()方法来处理消息。 三、源码结构 1.Handler的源码结构: public class Handler { private Looper mLooper; private MessageQueue mQueue; public Handler() { this(Looper.myLooper()); } public Handler(Looper looper) { mLooper = looper; mQueue = looper.
文章目录 前言1. oracle数据库1.1 表信息和注释信息1.2 表的列信息 2. mysql数据库2.1 常用的几个命令2.2 使用desc查看表结构2.3 表结构信息主要存在information_schema数据库2.4 主要表是columns,tables,schemata2.4.1 schemata 数据库信息2.4.2 tables表信息2.4.3 columns列信息 3.sqlsever数据库 前言 工作中如果和第三方做接口或者抽取数据,经常会用到不同的数据库的表结构信息以及列信息查询,本篇将简单总结一下oracle,mysql,sqlsever的表结构信息查询。
1. oracle数据库 1.1 表信息和注释信息 --查询出就3列,表名,表类型表或者视图,表注释 select * from user_tab_comments 1.2 表的列信息 SELECT * FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '表名' 输出信息包括:
列名称,列类型,列长度,精度等信息
2. mysql数据库 2.1 常用的几个命令 #查看数据库 show databases; # 使用数据库 use databasename; # 查看数据库下的表 show tables; # 查看表结构 desc table_name 2.2 使用desc查看表结构 mysql> desc psn; +---------+---------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------+---------+------+-----+---------+-------+ | id | int(11) | NO | | NULL | | | name | text | YES | | NULL | | | address | text | YES | | NULL | | +---------+---------+------+-----+---------+-------+ 2.
deepin解决没有无线驱动的问题 2023年6月6日更新 文中的deepin kernel版本是5.15,有该驱动问题。实测如果安装的deepin kernel版本是5.18,则没有该问题。
问题描述 时间:2023 年 6 月3 日
设备:联想小新 pro 16
主系统是 Windows 专业版,双系统安装好 deepin 后,wifi图标不显示,猜测是没有相应的驱动。
解决方法 打开 终端输入 lspci # 查看设备及驱动信息 我的无线网卡全名是Realtek Semiconductor Co., Ltd. RTL8852AE 802.11ax PCIe Wireless Network Adapter
因此,要下载该网卡对应的驱动文件,下面的文件是我在网上找到的,亲测有效。
下载解压后,进入解压后目录执行以下命令
make sudo make install sudo modprobe rtw89pci 如果没有其他错误,那么重启之后,wifi就恢复了。如果使用的Linux 版本更新,你可能需要重新执行上面的命令。
make clean make sudo make install sudo modprobe rtw89pci 参考文章链接https://askubuntu.com/questions/1379716/how-to-get-realtek-rtl8852ae-wifi-card-to-work-on-my-new-laptop
作业 取得每个部门最高薪水的人员名称
第一步:取得每个部门最高薪水(按照部门编号分组,找出每一组最大值) select deptno,max(sal) maxsal from emp group by deptno; +--------+---------+ | deptno | maxsal | +--------+---------+ | 20 | 3000.00 | | 30 | 2850.00 | | 10 | 5000.00 | +--------+---------+ 第二步:将以上结果当作临时表t,t表和emp e表进行连接, 条件是:t.deptno = e.deptno and t.maxsal = e.sal select e.ename,t.* from (select deptno,max(sal) maxsal from emp group by deptno) t join emp e on t.deptno = e.deptno and t.maxsal = e.sal; +-------+--------+---------+ | ename | deptno | maxsal | +-------+--------+---------+ | BLAKE | 30 | 2850.
前言:光阴似箭,岁月如梭。明天就是全国每年一次的高考了,我也即将结束我的大一生活成为一名大二的小学长啦嘿嘿。而我今天呢主要是想祝马上要高考的学弟学妹们高考顺利,金榜题名,并且借此机会顺便讲讲我的高考前后的故事哈哈。所以今天的文章是一篇没有代码的文章,纯文字哈哈,算是回顾自己的过去并记录一下吧!
📢📢📢我想说的 ⭐一、高考的来源⭐二、我的高考⭐三、我的大学⭐四、大二期许⭐五、高考加油 ⭐一、高考的来源 我国的高考,最早起源于隋朝开始的科举制度。 科举制度,是中国古代通过考试选拔官吏的制度。 由于采用分科取士的办法,所以叫做科举。 科举制从隋朝(一说唐朝)开始实行,直至清光绪卅一年(1905年)举行最后一科进士考试为止,前后经历一千三百余年,成为世界延续时间最长的选拔人才的办法。
⭐二、我的高考 我的高考嘛,一塌涂地的哈哈。怎么讲呢?对比高中时期的自己,我其实更喜欢现在的自己。因为过去的自己总是不够勇敢,不够果断。在还没有开始做一件事的时候就好像已经在做了一样感到焦虑,还没有开始一段感情的时候好像预见了结果而感到悲伤,还没有好好感受这一生呢,面见太阳的东升西落,会无端生出忧伤。我就像站在十字路口,一直在等待着,却始终没有行动。还记得高考前的几天,大家虽然对于即将到来的终点站感到紧张,但我能从中看到的是大家的激动与兴奋。是呀!怎么会不激动呢?十二年的寒窗苦读只为这一刻。度过后便能轻松愉快一段时间啦!
其实真正到了高考的那一刻反倒感觉没有那么紧张了,曾经的不甘与无奈都成为了前进的动力。反正我自己哈,当时高考的时候进考场前和进入考场后就是一种很轻松的状态,可能当时也是死马当活马医了吧哈哈。包括在考试开始的时候哇我感觉我自己贼自信,拿到试卷做题后感觉自己做的题都对了,不会做的胡乱搞两通感觉也能骗点分的。哈哈真的就感觉当时的自己已经达到了这世界的巅峰,现在回想来看有点迷之自信了吼吼。但既然过去了的就过去了,人总得往前走的嘛。
高考结束后的话当然是更加Crazy啦!有的人彻底放开,大玩特玩,有的人担忧自己的高考成绩,在考虑要不要复读,而我也有担忧我的高考成绩,有一点吧哈哈,因为觉得没啥了。然后就在家里吃饭、睡觉、打游戏,然后等着高考成绩公布。喔对啦,我们那年高考好像挺难的。高考成绩出来后有的人超常发挥从原本二本的程度上了一本,有的人严重失误从一本的程度掉落到卡在二本线的程度。我嘛,中规中矩,意料之中也在意料之外,我先说下我高中成绩不是很好哈。最后的话我就果不其然的上了一所双非二本学校哈哈,专业选的是计算机(软件),成为了一名程序猿。
⭐三、我的大学 在填选的学校以及该学校的计算机专业并被录取后,并且高考结束后的长达近乎三个月的暑假结束后,我进入了大学,开始了我的大学生活。我上的是外省的大学,所以出行啥的有点麻烦。在我的大一生涯刚开始的时候,因为在此之前我对于计算机这个专业并不是很了解,只听说这个专业好像挺吃香并且我的父母也觉得可以。在上了我们第一节专业课的时候我对编程产生了浓厚的兴趣,之后我主动担任了我们班专业课的课代表以及专业老师的学生助理。通过担任这些学生职位,组织过一次次大大小小的事情,以及参加了一些程序设计类的比赛,我的综合能力得到了很大的提升,也有一定的成就感。高中的我也爱玩游戏,熬夜,看小说,虽然学习的时候中午午休在那猛刷题,但是没有掌握方法和一定的毅力,现在看来当初那些自己以为的努力恐怕大多数都是“假努力”。而上了大学的我就不一样了,大一上我也是会玩游戏的,但是玩的少,因为迫于学习任务的压力以及想要变得优秀所以大一上绝大部分时间都在刷编程题。而大二下的我更是几乎不玩游戏了,因为我对于自己的目标和信念更加坚定,知道自己真正想要的是什么,不是像高中那样只会空想不行动。总体来说,我很庆幸大学的我没有和高中的那个我同流合污,高中的那些坏习惯在大学都已经在被我慢慢改掉。不再重蹈覆辙,在接下来的大学生活更加热爱自己,热爱生活,成为更好的自己!
⭐四、大二期许 然后先提前在这里为我的大二定下几个目标(嘻嘻)!
1、多参加比赛并拿奖2、做几个nb的项目3、提升自身的综合素质和能力4、健身(哈哈其实我觉得健身好像还蛮重要的,毕竟“身体是革命的本钱”,并且还能愉悦身心还能变强壮哈哈) 任何一件事情总得去做了才有成功的可能,做了就有50%的可能成功,不做的话就没有成功的可能了。反正都是平淡的日子,不妨肆无忌惮有趣一点呢!
我可以感到迷茫、无奈、失望,甚至堕落一段时间,但是绝不能放弃,因为一旦放弃就意味着再无可能了。
⭐五、高考加油 哈哈接下来真正进入正题。(讲着讲着就讲偏了哈哈)
祝高考的考生们:
高考一切顺利,做的都对,蒙的都对!
金榜题名!今年一定成功上岸!
💕 未来的路还很长,高考是一个终点站但绝对不仅仅是终点,还是起点。
源码编号:F-A14
项目类型:Java SE项目(GUI图形界面)
项目名称:商城购物系统,开源免费
用户类型:双角色(会员、管理员)
主要技术:java、awt、swing、等技术
开发工具:Eclipse
运行工具:Eclipse/MyEclipse/IDEA都可以,eclipse最兼容
数 据 库:MySQL5.7以上
项目简介:本系统主要的功能有会员注册、登录、商品种类管理、商品管理、浏览商品、以及购物车等操作。
以下是部分截图
项目骨架
主界面
登录
添加商品类别
商品管理
以下是核心代码
package com.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.model.Customer; import com.model.ManagerUser; public class CustomerUserDao { public int customerAdd(Connection con,Customer customer)throws Exception{ String sql="insert into t_customer values(null,?,?,?,?)"; PreparedStatement pstmt=con.prepareStatement(sql); pstmt.setString(1, customer.getCustomerName()); pstmt.setString(2, customer.getPassword1()); pstmt.setString(3, customer.getPassword2()); pstmt.setFloat(4, customer.getMoney()); return pstmt.executeUpdate(); } public Customer login(Connection con, Customer customer)throws Exception{ Customer resultUser=null; String sql="
基本思想:业务需求,需要实例分割检测案例,选定yolov8模型训练自己业务场景数据集。
一、拉取官方源码
git clone https://github.com/ultralytics/ultralytics 二、数据准备
数据及结构
对数据集进行转换和划分。注意:将图片和json文件放在不同的文件夹里。如下图所示,另外新建两个文件夹txt和split文件夹。
注意标签是: 类别 x坐标 y坐标 …(中间有空格,并且坐标除以了原图图片大小,归一化后的)这是实例分割的数据要求。
my_datasets ├── images # 原始图片 ├── json # 对应json文件 ├── split # 划分后的数据集 │ ├── images │ │ ├── test │ │ ├── train │ │ └── val │ └── labels │ ├── test │ ├── train │ └── val └── txt # 存放标签 (归一化后的值) 形式:ids x y x y ... 2.1 将json文件转换为txt格式
json2txt.py
# -*- coding: utf-8 -*- import json import os import argparse from tqdm import tqdm def convert_label_json(json_dir, save_dir, classes): json_paths = os.
原文链接
介绍 nsenter是用来进入容器内部的一个命令,它的优势之处在于可以自己选择加载容器的那些namespaces。 说直白一点就是 排查docker容器可以具备inux宿主命令的的方法。 一典型的用途容器网络命令空间。容器为了轻量级,不包含基础的命令,如说 ip address,ping,telnet,ss,tcpdump 等,给调试容器网络带来很大困扰:只能通过 docker inspect ContainerID 获取容器IP,无法测试和其他网络的连通性。这时使用nsenter命令仅进入该容器的网络命名空间,使用宿主机的命令调试容器网络。nsenter也可以进入 mnt, uts, ipc, pid, user 命令空间,指定根目录和工作目录。 namespace是Linux中一些进程的属性的作用域,使用命名空间,可以隔离不同的进程。 1、nsenter的安装 yum install util-linux -y 2、nsenter的使用 [root@localhost ~]# nsenter --help 用法: nsenter [options] <program> [<argument>...] Run a program with namespaces of other processes. 选项: -t, --target <pid> 要获取名字空间的目标进程 -m, --mount[=<file>] enter mount namespace -u, --uts[=<file>] enter UTS namespace (hostname etc) -i, --ipc[=<file>] enter System V IPC namespace -n, --net[=<file>] enter network namespace -p, --pid[=<file>] enter pid namespace -U, --user[=<file>] enter user namespace -S, --setuid <uid> set uid in entered namespace -G, --setgid <gid> set gid in entered namespace --preserve-credentials do not touch uids or gids -r, --root[=<dir>] set the root directory -w, --wd[=<dir>] set the working directory -F, --no-fork 执行 <程序> 前不 fork -Z, --follow-context set SELinux context according to --target PID -h, --help 显示此帮助并退出 -V, --version 输出版本信息并退出 中文说明 --mount参数是进去到mount namespace中 --uts参数是进入到uts namespace中 --ipc参数是进入到System V IPC namaspace中 --net参数是进入到network namespace中 --pid参数是进入到pid namespace中 --user参数是进入到user namespace中 nsenter命令要获取到docker容器的进程,然后再使用nsenter工具进去到docker容器中 # docker inspect -f {{.
复制:
在Linux中,要把文件"/home/qin/test_7_qin/source_update20221108/source_update20221108/Makefile "复制到"/home/qin/test_8_stsutsumi/Makefile",使用带有源文件和目的文件绝对路径的 "cp "命令。
cp /home/qin/test_7_qin/source_update20221108/source_update20221108/Makefile /home/qin/test_8_stsutsumi/Makefile 注意,如果目标目录不存在,"cp "命令将创建它。如果目标文件已经存在,"cp "命令将不加警告地覆盖它,除非你使用"-i "选项在覆盖前提示确认。
如果你想保留原文件的属性,例如权限,你可以使用"-p "选项:
cp -p /home/qin/test_7_qin/source_update20221108/source_update20221108/Makefile /home/qin/test_8_stsutsumi/Makefile 在Linux中,"... "的语法用来表示当前目录的源目录。因此,使用 "cp "命令从源目录复制一个文件,你需要用"... "指定文件的路径,以便在目录树中向上移动。例如,如果你想从当前目录的源目录复制一个名为 "example.txt "的文件到当前目录,你可以使用以下命令:
cp ../example.txt . 如果你想使用相对路径来复制文件,你可以使用下面的命令:
cp ../../test_7_qin/source_update20221108/source_update20221108/Makefile ../test_8_stsutsumi/Makefile 这个命令假定当前位于"/home/qin/test_8_stsutsumi/"目录下,并且源文件位于"/home/qin/test_7_qin/source_update20221108/source_update20221108/"目录下。它使用相对路径来指定源文件和目标文件的位置。
报错:
cp: cannot stat `../../test_7_qin/source_update20221108/source_update20221108/Makefile': No such file or directory
表示 "cp "命令无法找到你试图复制的文件。
确保你使用的是从当前目录到该文件的正确相对路径。你可以使用 "pwd "命令来打印当前目录的路径,然后使用相对路径语法来导航到文件。
例如,如果你的当前目录是"/home/qin/test_8_stsutsumi/",而你要复制的文件位于"/home/qin/test_7_qin/source_update20221108/source_update20221108/Makefile",你可以使用以下命令:
该命令使用相对路径导航到文件,从当前目录开始,用".../"向上移动两级。然后它指定目标目录和文件名的完整路径。
出现 "cp: omitting directory... "的信息,但你将一个目录作为源文件或目的地。
因为它只对文件而不是目录起作用。
要复制一个目录及其内容,你可以使用带有-r(递归)选项的cp命令,该选项告诉该命令以递归方式复制目录及其内容:
bash
复制代码
cp -r /home/qin/test_8_stsutsumi /path/to/destination/
用你想复制/home/qin/test_8_stsutsumi内容的目录的路径来替换/path/to/destination/。
移到最後一行::$
tail -n N filename
Docker 基础使用 认识Docker 没有Docker存在的问题
– 部署流程繁琐
– 环境不一致
– 资源隔离问题
– 交付流程复杂
– 核心概念
什么是docker 容器的概念在软件行业应用很广,比如我们经常使用的 Tomcat 容器,以及我们 Java 开发所使用的 Spring 容器。而今天我们所介绍的容器,又在这二者之上,是基于操作系统特性所实现的容器化技术。它与 Tomcat 类似,也是用于存放应用的容器。别在于 Tomcat 仅仅用于存放 Servlet 应用,而基于操作系统所实现的容器化技术所构建的容器,可以存放几乎所有应用。
在这一层面,可以**将容器理解为通过操作系统的容器化技术,所构建出来的一套独立的软件运行时环境。在这套环境中集成了要运行的软件所依赖的所有其他应用、工具等。它是一个标准化的独立空间,容器内的一切工具、应用是以为容器中的主应用运行而生的。****
应用容器化以后,将具有以下两大特性:
标准化 一个应用运行时期所需要的所有本地环境信息(工具、依赖等)都将集成在一个容器中,因此任意一台服务器只要支持容器化技术,都能够轻易的将一个应用直接部署起来。
隔离性 容器中的环境信息与其他容器,甚至是宿主机之间都是隔离的。这个隔离包括了网络、文件系统、内存、硬盘和CPU等等关键硬件资源。我们可以在一台机器上部署多个容器,而多个容器中分别运行着不同版本 JDK 的 Java 应用,它们之间不会存在任何冲突问题。
一、容器—>运行的软件 拥有了标准化与隔离性,就意味着我们可以轻松的为需要部署的应用构建一套独立的运行环境,且可以在任意支持容器运行的环境中快速部署我们的应用,提高应用的交付能力
容器VS虚拟机 容器是应用程序的抽象,将应用程序代码与环境打包在一起构建一套独立的运行环境,多个容器可以在一台计算机上运行并且与其他容器共享OS内核。且每个容器之间利用用户空间来进行资源隔离,相对于操作系统来说是非常轻量的。
而虚拟机则完全是对于一台计算机的抽象,一个操作系统上可以运行多个虚拟机,但每个虚拟机都是一个独立运行的操作系统,且有着完整的一套基于硬件设备的虚拟设备进行资源的隔离,这样的抽象方式导致虚拟机无论是在运行时的资源损耗还是启动的效率都是非常重量级的操作。
二、镜像—>软件的安装包 可以理解为就是一个软件安装包,在这个安装包中压缩了软件运行时需要的所有资源(依赖、配置、图片等)
三、仓库—>应用商店 仓库是用于存放非镜像的地方,类似于 Maven 仓库、Git 仓库等用途。仓库之上还有**仓库注册服务器(Registry)**的概念,上面可以存放着多个仓库,每个仓库中又有多个镜像,而每个镜像又可以有多个标签(tag)。目前Docker 官方的公开仓库是 Docker Hub,我们可以使用类似 Git 命令的方式去 pull/push 镜像
四、Docker的架构 C/S 架构 Client 客户端 、Server 服务端
客服端:向服务端发起请求,要求服务端处理某些数据,或获取指定数据
Server:接收客户端请求,处理客户端请求,响应处理结果
Docker Client Docker 客户端 向服务端发起请求,比如下载镜像,管理容器生命周期等操作
准备:centos7环境,并且能链接网络配置好yum源
打开终端,并以root用户身份登录或使用sudo权限。
1、在终端中运行以下命令,以确保系统是最新的:
yum update 2、使用以下命令安装JDK 1.8软件包:
yum install java-1.8.0-openjdk-devel 这将安装JDK 1.8及其开发工具。
3、安装过程完成后,可以通过以下命令验证Java安装是否成功:
java -version 如果安装成功,将显示Java版本信息。
如果您希望将JDK 1.8设置为默认的Java版本,可以运行以下命令:
alternatives --config java
然后,从列表中选择JDK 1.8的编号,并按照提示进行操作。
这样,您就成功在CentOS 7上安装了JDK 1.8请记住,此过程假定您的系统已正确配置并连接到互联网,以便从软件仓库中下载和安装所需的软件包。
目录
7-1 jmu-Java-05集合-01-ListIntegerStack
main方法说明
思考:
输入样例
输出样例
7-2 jmu-Java-05集合(泛型)-10-GeneralStack
1. 编写一个通用的GeneralStack接口,接口中的操作对任何引用类型的数据都适用。
2.定义GeneralStack的实现类ArrayListGeneralStack
3.定义Car对象
4.main方法说明
输入样例
输出样例
7-3 jmu-Java-05集合-4-倒排索引
输入说明
输出说明
输入样例
输出样例
7-4 jmu-Java-m06 统计一篇英文文章中出现的不重复单词的个数
输入格式:
输出格式:
输入样例:
输出样例:
7-5 sdut-String+array(LinkedHashMap) 读中国载人航天史,汇航天员数量,向航天员致敬(1)
输入格式:
输出格式:
输入样例:
输出样例:
7-6 sdut-Map(dict)-String--单词和字符鉴别器
输入格式:
输出格式:
输入样例:
输出样例:
7-1 jmu-Java-05集合-01-ListIntegerStack 分数 15
全屏浏览题目
切换布局
作者 郑如滨
单位 集美大学
定义IntegerStack接口,该接口描述了一个存放Integer的栈的常见方法:
public Integer push(Integer item); //如item为null,则不入栈直接返回null。否则直接入栈,然后返回item。 public Integer pop(); //出栈,如栈为空,则返回null。 public Integer peek(); //获得栈顶元素,如栈顶为空,则返回null。注意:不要出栈 public boolean empty(); //如过栈为空返回true public int size(); //返回栈中元素数量
目录
7-1 jmu-java-m05-自定义Judgeable接口
Person类
自定义接口Judgeable
main类
输入格式:
输出格式:
输入样例:
输出样例:
7-2 sdut-String-5 图书价格汇总(II)
输入格式:
输出格式:
输入样例:
输出样例:
7-3 两种异常捕获小程序
输入格式:
输出格式:
输入样例1:
输出样例1:
输入样例2:
输出样例2:
输入样例3:
输出样例3:
7-4 计算长方体和四棱锥的表面积和体积
输入格式:
输出格式:
输入样例:
输出样例:
7-5 设计一个学生类和它的一个子类——本科生类
输入格式:
输出格式:
输入样例:
输出样例:
7-6 定义接口(Biology、Animal)、类(Person)、子类(Pupil)
输入格式:
输出格式:
输入样例:
输出样例:
7-7 利用正则表达式得到一段HTML文本中所有超链接对应的网址
输入格式:
输出格式:
输入样例:
输出样例:
7-8 jmu-Java-02基本语法-07-大整数相加
输入格式
输入样例:
输出样例:
7-1 jmu-java-m05-自定义Judgeable接口 分数 10
全屏浏览题目
切换布局
作者 郑如滨
单位 集美大学
该程序包含
Person类 属性:String name,boolean gender String birthdate。
1、对当前数据库启用cdc -- 对当前数据库启用cdc USE database GO EXECUTE sys.sp_cdc_enable_db; GO 2、报错:因为当前数据库中已存在名为 'cdc' 的数据库用户或名为 'cdc' 的架构,所以无法为.... 这种情况是因为附加过来的数据库已经开启了CDC,已经存在了CDC命名的架构和用户。
3、方法:删除掉CDC架构和用户。 点击删除CDC命名的架构会报错3729: 删除对于架构cdc"失败。 (Microsoft.SqlServer.Smo)其他信息:,执行Transact-SQL...
4、执行 select * from sys.objects obj join sys.schemas s on(s.schema_id = obj.schema_id) where s.name = 'cdc' order by obj.name 找到关联的这个name,删除掉:
--type为IF的删除格式fn_cdc_get_all_changes_dbo_general_order为name名 drop function cdc.[fn_cdc_get_all_changes_dbo_general_order]; --type为P的删除方式sp_upd_18151160为name名 drop procedure cdc.sp_upd_18151160; 5、将CDC所关联的删掉后,再删除CDC名称的架构和用户,用户删不掉改个名字也行。再执行开启库CDC开启成功。 6、查看数据库开启CDC是否成功。 --database数据库名,查询 1 开启成功 select is_cdc_enabled from sys.databases where name='database'
静态IP(Static IP)和动态IP(Dynamic IP)是Internet Protocol(IP)地址的两种类型。
静态IP的特点是固定不变,由Internet服务提供商(ISP)或网络管理员手动配置和分配给每个设备。它在网络中具有永久的、独特的标识符,不会改变,需要手动配置网络设置。静态IP通常用于需要远程访问或需要稳定、可靠连接的设备,如服务器、路由器、交换机或网络打印机等。
动态IP的特点是动态变化,由ISP动态分配给设备,在设备每次连接到Internet时会自动获得一个新的IP地址。动态IP通常用于普通家庭和办公室的设备,例如个人电脑、笔记本电脑、手机和平板电脑等。
以下是静态IP和动态IP之间的对比:
1.分配方式:静态IP由ISP或网络管理员手动分配,而动态IP由ISP动态分配。
2.稳定性:静态IP比动态IP更稳定,因为它们不会随意更改,不受ISP动态分配IP地址的影响。
3.安全性:由于静态IP具有固定的、独特的标识符,攻击者更容易跟踪和攻击特定的设备和网络,而动态IP则具有更高的安全性。
4.可远程访问性:静态IP适用于需要远程访问的设备,如服务器和路由器等。动态IP不适用于远程访问,因为每次连接时都会更改IP地址。
5.成本:静态IP的成本较高,因为需要手动分配和配置。动态IP的成本较低,因为ISP可以使用动态IP池动态分配IP地址。
总的来说,静态IP和动态IP各有优劣,具体选择哪种类型取决于网络需求和使用场景。
CentOS 7的服务管理使用了systemd,它是一个与服务管理相关的极为强大的工具,可用于管理操作系统中正在运行的各种服务、进程和资源。以下是CentOS 7中使用systemd管理服务的方式:
启动服务:启动服务使用systemctl命令,例如,启动httpd服务可以使用命令“systemctl start httpd.service”。
停止服务:停止服务使用systemctl命令,例如,停止httpd服务可以使用命令“systemctl stop httpd.service”。
重启服务:重启服务使用systemctl命令,例如,重启httpd服务可以使用命令“systemctl restart httpd.service”。
查看服务状态:查看服务状态使用systemctl命令,例如,查看httpd服务状态可以使用命令“systemctl status httpd.service”。
设置服务启动项:启用/禁用服务的开机启动使用systemctl命令,例如,启用httpd服务的开机启动可以使用命令“systemctl enable httpd.service”,禁用httpd服务的开机启动可以使用命令“systemctl disable httpd.service”。
查看服务启动项:查看已启用的服务启动项使用systemctl命令,例如,查看已启用的httpd服务启动项可以使用命令“systemctl list-unit-files --type=service | grep httpd”。
查看服务日志:查看服务日志使用journalctl命令,例如,查看httpd服务的日志可以使用命令“journalctl -u httpd.service”。
总的来说,CentOS 7的服务管理借助于systemd变得更加强大和灵活,可以更方便地管理操作系统中的各种服务和资源。
管道符是一种在Unix和类Unix操作系统中使用的特殊符号,用于连接命令并将一个命令的输出作为另一个命令的输入。它的符号是“|”。
管道符的工作原理如下:
输入命令:用户在命令行中输入一个或多个命令,并使用管道符“|”来连接它们。每个命令都将执行一个特定的任务。
执行第一个命令:第一个命令将运行并生成一些输出。输出可以是文件内容、命令返回的数据等等。
传递输出:管道符“|”将第一个命令的输出传递给下一个命令作为输入。
执行第二个命令:第二个命令使用第一个命令的输出作为输入,并对其进行处理,生成另外一些输出。
重复执行:如果有更多的命令需要执行,则继续使用管道符“|”将它们连接起来,以便它们可以接收前面命令的输出并生成它们自己的输出。
输出结果:最后一个命令将生成一个最终输出,它通常会在终端上打印出来,或者可以输出到文件中。
通过使用管道符,用户可以将命令组合起来执行更复杂的任务。管道符是Unix和类Unix操作系统中强大的编程工具之一,可以大大提高生产效率
上传组件 <el-upload :action="uploadUrl" :headers="headers" list-type="picture" :multiple="false" :show-file-list="showFileList" :file-list="fileList" :on-remove="handleRemove" :on-success="handleUploadSuccess" :on-preview="handlePreview" :before-upload="beforeAvatarUpload" > <el-button type="primary">点击上传</el-button> </el-upload> 上传前的校验钩子函数 beforeAvatarUpload(file) { console.log(file.type) const isLt2M = file.size / 1024 / 1024 < 10 const isJPG = file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg' if (!isJPG) { this.$message.error('上传图片只能是 JPG/PNG 格式!') } if (!isLt2M) { this.$message.error('上传图片大小不能超过 10MB!') } return isLt2M && isJPG }
网上看过太多关于MethodHandle方法句柄的文章,但是基本上没有人能把其中的findspecial方法讲清楚,特别是findspecial的第四个参数specialCaller, 相信大家都不明白是干嘛用的,网上给出的水文是很多都是说: 执行到specialCaller的父类所对应的方法。我可以很负责的告知各位:这个结论绝对是错误的!
包括网上很知名的书籍《深入理解java虚拟机》也并没有把这个问题讲清楚,这本书废话太多,对于关键问题讲不到重点,完全是浪费读者时间。
首先我给出一个结论:findspecial的第四个参数specialCaller的作用:是为了限定方法查找的范围。
public MethodHandle findSpecial(Class<?> refc, String name, MethodType type, Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException 后面会通过走读源码具体说明这一点。
首先我们需要了解,MethodHandle方法句柄中lookup到底是起什么作用的,因为包括findstatic,findvirtual,findspecial这些都是从lookup中创建出来。
官网的解释如下:
A lookup object is a factory for creating method handles, when the creation requires access checking. Method handles do not perform access checks when they are called, but rather when they are created. Therefore, method handle access restrictions must be enforced when a method handle is created. The caller class against which those restrictions are enforced is known as the lookup class.
目录
Node & System/Software Lists
Architecture Overview of Harbor
Install Harbor 2.8
Harbor Installation Prerequisites
Install Docker and Docker Compose
Install Harbor
Pull and Push image from Harbor
Reference documentation Node & System/Software Lists HOSTNAME
IPNODE TYPECONFIGmaster1192.168.1.100harbor server4vCPU4G SystemVersion
kernel3.10.0-1160.el7.x86_64centosCentOS Linux release 7.9.2009 (Core) Software NameVersiondocker24.0.2docker composev2.18.1harborv2.8.1 Architecture Overview of Harbor With Harbor V2.0, users can manage images, manifest lists, Helm charts, CNABs, OPAs among others which all adhere to the OCI image specification.
elasticsearch-索引生命周期管理 索引生命周期分为4个阶段:hot、warm、cold、delete
其中hot阶段主要负责对索引进行滚动更新操作,warm、cold、delete阶段主要负责进一步处理滚动更新后的数据
阶段介绍hot热数据阶段,主要处理时序数据的实时写入。可根据索引的文档数、大小、时长决定是否调用rollover API来滚动更新索引warm冷数据阶段,索引不再写入,主要用来提供查询cold冷数据阶段,索引不再更新,查询很少,查询速度会变慢delete删除数据阶段,索引将被删除 添加生命周期管理方式 通过索引模板添加生命周期管理策略
将策略应用到整个别名覆盖的索引下
为单个索引添加生命周期管理策略
只能覆盖当前索引,新滚动的索引不再受策略影响
生命周期操作 参数说明rollover当写入索引达到了一定的大小,文档数量或创建时间时,rollover可创建一个新的写入索引,将旧的写入索引的别名去掉,并把别名赋给新的写入索引。所以便可以通过切换别名控制写入的索引是谁。它可用于Hot阶段shrink减少一个索引的主分片数,可用于Warm阶段。需要注意的是当shink完成后索引名会由原来的<origin-index-name>变为shrink-<origin-index-name>force merge可触发一个索引分片的segment merge,同时释放掉被删除文档的占用空间。用于Warm阶段allocate可指定一个索引的副本数,用于warm, cold阶段delete删除索引,用户delete阶段 配置索引生命周期 第一步:配置lifecycle检测时间;第二步:创建一个索引策略;第三步:创建一个索引模版,指定使用的索引策略;第四步:创建一个符合上述索引模版的索引;第五步:向索引中写入数据,使索引触发滚动更新策略;第六步:查看索引所处阶段 1.配置lifecycle检测时间
PUT /_cluster/settings { "transient": { "indices.lifecycle.poll_interval": "1s" } } 2.创建一个索引策略
PUT /_ilm/policy/lfc_test { "policy": { //阶段设置 "phases": { "hot": { "actions": { "rollover": { "max_docs": "5" } } }, "warm": { "min_age": "10s", "actions": { "allocate": { "number_of_replicas": 0 } } }, "delete": { "min_age": "20s", "actions": { "delete": {} } } } } } 3.
"Authorization: Bearer" 是一种在 HTTP 请求头部中用于传递访问令牌(Access Token)的常见格式。它用于在客户端和服务器之间进行身份验证和授权操作。
底层原理是这样的:当客户端发送 HTTP 请求时,可以在请求头部中添加 "Authorization" 字段来传递访问令牌。"Bearer" 是一种认证方案(authentication scheme)的名称,用于指示后面的令牌是访问令牌。
例如,如果你有一个名为 "your_access_token" 的访问令牌,你可以通过设置请求头部的 "Authorization" 字段来传递它:
Authorization: Bearer your_access_token 服务器在接收到请求时,可以读取 "Authorization" 字段,并解析出令牌部分,即 "your_access_token"。然后,服务器可以使用该令牌进行身份验证和授权操作。
使用 "Authorization: Bearer" 的形式可以带来一些好处:
一致性:它遵循了 HTTP 规范中关于认证方案的标准格式,使得在不同的系统和框架之间可以更好地进行互操作性。可扩展性:"Bearer" 方案可以与不同类型的令牌一起使用,如基于 JSON Web Token (JWT) 的令牌,OAuth 2.0 的访问令牌等。安全性:通过将访问令牌放置在请求头部中,可以避免令牌泄露在 URL 参数或请求主体中的潜在风险。 需要注意的是,"Bearer" 方案本身并不提供加密或验证令牌的机制,它只是一种用于标识令牌类型的约定。实际的令牌验证和授权逻辑需要在服务器端进行,根据具体的身份验证和授权方案进行处理。
总结来说,"Authorization: Bearer" 是一种在 HTTP 请求头部中用于传递访问令牌的格式。它指示后面的令牌是访问令牌,服务器可以读取并使用该令牌进行身份验证和授权操作。它提供了一种标准化和可扩展的方式来传递访问令牌,并提高了安全性和互操作性。
排查系统满问题 1. 自身的电脑的系统盘经常被撑满主要基于如下原因:
(1)安装的软件直接部署到系统盘导致,建议将软件安装到其他盘符
(2)默认下载的软件文本存储目录在系统盘,建议挪到其他盘符
(3)部署安装有docker desktop软件,此时若访问%LOCALAPPDATA%/Docker/wsl目录,可以看到两个文件夹,每个文件夹都会有一个vhdx文件,并且在我自己的环境下,其中docker-desktop-data存放镜像的文件竟然达到34.2GB,docker-desktop用于存放程序的也近600M.
故而在当前环境下将上述的vhdx文件挪到其他盘符,整个操作过程如下所示
Step1:停止并删除所有容器 docker rm `docker ps -a -q` Step2:退出docker desktop Step3: 使用cmd关闭所有发行版本 wsl --list --verbose 【查看所有发行版本状态】 wsl --shutdown wsl --list --verbose 【查看所有发行版本状态】 Step4:备份已有镜像信息 wsl --export docker-desktop-data D:\appsoft\docker_data\docker-desktop-data.tar Step5: 备份程序 wsl --export docker-desktop D:\appsoft\docker_data\docker-desktop.tar Step6:注销当前的发行版本 wsl --unregister docker-desktop-data wsl --unregister docker-desktop Step7: 重新导入备份的docker-desktop-data和docker-desktop wsl --import docker-desktop-data D:\appsoft\docker_data\ D:\appsoft\docker_data\docker-desktop-data.tar --version 2 wsl --import docker-desktop D:\appsoft\docker_data\distro D:\appsoft\docker_data\docker-desktop.tar --version 2 Step8: wsl --list --verbose命令验证发行版本是否恢复 Step9:重启docker-desktop 参考资料 How can I change the location of docker images when using Docker Desktop on WSL2 with Windows 10 Home?
Gradle项目打包,包含依赖 最近有在看mirai项目,失业在家有一段时间了,恰巧现在经济危机,到处都找不到工作,就索性在家里玩一会。然后遇到一个打包的问题。但是到处都没有就很离谱。还是记录一下
下面这样就可以生成一个可以用的包
plugins { id 'com.github.johnrengelman.shadow' version '7.0.0' } // ./gradlew shadowJar 命令 生成可执行jar包 shadowJar { baseName = 'liliya-bot' version = '1.0-SNAPSHOT' classifier = null manifest { attributes 'Main-Class': 'com.example.Main' } } 第一行是导入插件第二行是jar包的名字第三行版本号第四行指定了生成的jar包不包含任何分类信息。第五行指定了生成的jar包的主类为com.example.Main。 完整的一个gradle.build 如下,仅供参考
使用这个命令 ./gradlew shadowJar 开始打包
出现 BUILD SUCCESSFUL 就是打包成功了
build成功之后在项目下会出现一个build文件夹,打好的jar包出现在这里。然后就可以 java -jar 来使用了
目录
面向对象程序设计——Java语言_浙江大学_中国大学MOOC(慕课)
一、继承
1.1 案例
1.2 继承语法
1.3 子类与父类的关系
二、多态
2.1 多态变量
2.2 子类的对象可以被看作是父类的对象来使用
2.3 造型
三、类型系统
3.1 Object 类
3.2 equals() 比较两个对象内容是否相同
3.3 DoME的新媒体类型
四、继承类型
五、其他关键字
5.1 implements
5.2 final
一、继承 面向对象程序设计语言(Object Oriented Programming)OOP /uːp/ 有三大特性:封装、继承和多态性。继承是 Java 中实现软件重用的重要手段,是 java 面向对象编程技术的一块基石。因为它允许创建分等级层次的类。继承是非常简单而强大的设计思想,它提供了我们代码重用和程序组织的有力工具。没有继承的语言只能被称作“使用对象的语言”。
类是规则,用来制造对象的规则。我们不断地定义类,用定义的类制造一些对象。类定义了对象的属性和行为,就像图纸决定了房子要盖成什么样子。一张图纸可以盖很多房子,它们都是相同的房子,但是坐落在不同的地方,会有不同的人住在里面。
假如现在我们想盖一座新房子,和以前盖的房子很相似,但是稍微有点不同。一般建筑师都会拿以前盖的房子的图纸来,稍加修改,成为一张新图纸,然后盖这座新房子。所以一旦我们有了一张设计良好的图纸(有共同的特征和动作放在一个类的通用类,让其它类共享),我们就可以基于这张图纸设计出很多相似但不完全相同的房子的图纸来(扩展为其他多个继承了通用类中的特征和动作的特定类)。父类更通用,子类更具体。
基于已有的设计创造新的设计,就是面向对象程序设计中的继承。在继承中,新的类不是凭空产生的,而是基于一个已经存在的类而定义出来的。通过继承,新的类自动获得了基础类中所有的成员,包括成员变量和方法,包括各种访问属性的成员,无论是 public还是 private(但不能访问)。当然,在这之后,程序员还可以加入自己的新的成员,包括变量和方法。显然,通过继承来定义新的类,远比从头开始写一个新的类要简单快捷和方便。
1.1 案例 实现一个媒体资料库database,用来存所有张 CD 以及 DVD 的数据。 1.1.1 组织程序
每一个CD/DVD对象的内容信息的存储--> 由 class CD \ class DVD 执行;
对每一个CD/DVD对象进行的操作(包括增加、查询等)-- > 由 class database 控制;
1 定位过程 CPU飙升问题定位的一般步骤是:
首先通过top指令查看当前占用CPU较高的进程PID查看当前进程消耗资源的线程PID:top -Hp PID通过print命令将线程PID转为16进制,根据该16进制值去打印的堆栈日志内查询,查看该线程所驻留的方法位置通过jstack命令,查看栈信息,定位到线程对应的具体代码分析代码解决问题 2 常见原因及解决方案 如果是空循环,或者空自旋。
处理方式:可以使用Thread.sleep或者加锁,让线程适当的阻塞。
在循环的代码逻辑中,创建大量的新对象导致频繁GC。比如,从mysql查出了大量的数据,比如100W以上等等。
处理方式:可以减少对象的创建数量,或者,可以考虑使用 对象池。
其他的一些造成CPU飙升的场景,比如 selector空轮训导致CPU飙升 。
处理方式:参考Netty源码,无效的事件查询到了一定的次数,进行 selector 重建。
3 正式案例 3.1 采用top命令定位进程 登录服务器,执行top命令,查看CPU占用情况,找到进程的pid
top 很容易发现,PID为29706的java进程的CPU飙升到700%多,且一直降不下来,很显然出现了问题。
3.2 使用top -Hp命令定位线程 使用 top -Hp <pid> 命令(为Java进程的id号)查看该Java进程内所有线程的资源占用情况
tip: 按shft+p按照cpu占用进行排序,按shift+m按照内存占用进行排序
top -Hp 29706 不难发现,多个线程的CPU占用达到了90%多。我们挑选线程号为30309的线程继续分析
3.3 使用jstack命令定位代码 3.3.1 线程号转换为16进制 可以使用 printf “%x\n” 命令(tid指线程的id号)将以上10进制的线程号转换为16进制
printf "%x\n" 转换后的结果分别为7665,由于导出的线程快照中线程的nid是16进制的,而16进制以0x开头,所以对应的16进制的线程号nid为0x7665
3.3.2 采用jstack命令导出线程快照 通过使用jdk自带命令jstack获取该java进程的线程快照并输入到文件中
注意:open jdk不带该命令|没有注册环境变量的,需要对应的java目录执行jstack命令
jstack -l 进程ID > ./jstack_result.txt 命令(为Java进程的id号)来获取线程快照结果并输入到指定文件
jstack -l 29706 > ./jstack_result.txt 3.3.3 根据线程号定位具体代码 在jstack_result.
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录 一、新建虚拟机二、进行安装CentOS7.9总结 一、新建虚拟机 磁盘大小可更改 点击CD 开启虚拟机 二、进行安装CentOS7.9 选择第一个 凡是有叹号的地方都要点 后两步密码过于简单需要点击两边完成 安装完成后重新启动 后三步可选跳过 总结 以上是虚拟机CentOS9.7的安装步骤,需在新建虚拟机的基础上进行,初步可建立中文版,当熟练掌握后可安装英文版练习加深印象。(如是英语大师请忽略此条件)
1.前言 笔者最近在阅读TIMESNET这篇论文,但在阅读代码的过程中发现了一些问题,其在reshape的细节上可能与原论文的叙述出现了一些偏差,不知道是不是笔者本人的误解,故记录,与供感兴趣的同学进一步探讨。
2.简介 本文是ICLR2023的一篇论文,主要是提出了一种新的时间建模思路,即将一维的时间序列通过快速傅里叶变换求得多个周期(根据频域峰值确定周期),然后将原始的一维时间序列reshape成二维的周期序列,如:一个10帧的时间序列,求得周期为2,则将其reshape成一个[2,5]的时间序列,这样就可以使用二维的卷积核捕捉周期内的信息,以及周期间的信息。而传统的一维卷积核,只能聚合相邻帧之间的信息,无法实现对周期性信息的建模。文章在多种时间序列任务上均取得了不错的效果,且笔者觉得思路非常有趣,具体的细节值得各位亲自阅读,这里不再赘述。
3.代码的一处细节疑问 根据论文作者给出的开源代码,笔者进一步进行了研究,发现在/model/TimesNet.py内有这样一处:
# reshape out = out.reshape(B, length // period, period, N).permute(0, 3, 1, 2).contiguous() # 2D conv: from 1d Variation to 2d Variation out = self.conv(out) 其中,out 是输入的时间序列,B 为 batch,length 为时间序列长度,period 为文中方法计算的周期,length // period 则为一个周期的长度,N为通道数。不难发现,reshape 后形为[B, N, length // period,period],为了方便理解,我们省去B,并做一个简单的模拟,看一看结果。
首先,我们模拟一个[3,10]的信号,表示3通道,10帧的一个时间序列:
图1. 模拟信号
假设我们算出周期为2,则应reshape为 [3,5,2]:
图2. reshape之后的信号
图1表明了,第一个通道上这个时间序列的顺序是0.7138, 0.5638, 0.0741, 0.3191, 0.2234, 0.9412, 0.7298, 0.6380, 0.7597,0.3348,那根据原论文的意思,笔者理解为应该reshape为[3,2,5]:
图3. 笔者认为的reshape方法
因为,如果想建立周期内的信息和周期间的信息,比如说我用一个2*2的卷积核,是不是应该扫过第1、2和第6、7帧,因为对于上述例子,第1帧和第6帧分别是两个周期的开始,论文是希望建立这两者的连接,但是如果按照作者给出的代码,得到图2的reshape结果,是否在卷积核扫过的时候,包括在内的是第1、2、3、4帧,这样的卷积方式,似乎跟一维的TCN没有什么区别。
不知道是笔者理解错误还是代码出现了一些瑕疵,期待各位探讨指正。
1.通过Android studio导出aab包 证书和项目和输出路径貌似要在同一路径下,否则报错'other' has different root
目前这样可以
2.下载bundletool.jar 下载地址:
Releases · google/bundletool · GitHub
并配好java环境变量,以及adb环境变量
3.生成apks java -jar bundletool-all-1.15.1.jar build-apks --bundle=xxx.aab --output=xxx.apks --ks=xxxx.jks --ks-pass=pass:证书密码 --ks-key-alias=证书别名 --key-pass=pass:证书别名密码 4.安装到手机 java -jar bundletool-all-1.15.1.jar install-apks --apks=xxx.apks
下载Microsoft Build Tools for Visual Studio 2019.
选择C++桌面开发,右边选MSVC v142 和 Windows 11 SDK
开放式漏洞评估系统OpenVAS:Open Vulnerability Assessment System
OpenVAS是开放式漏洞评估系统,也可以说它是一个包含着相关工具的网络扫描器。其核心部件是一个服务器,包括一套网络漏洞测试程序,可以检测远程系统和应用程序中的安全问题,是由若干服务和工具组成的框架,提供全面而强大的漏洞扫描和漏洞管理功能。它是开源的,可以免费使用。它有一个客户端-服务器架构的web接口。server组件用来调度扫描任务和管理插件,client组件用于配置扫描和查看报告。
包含如下特点:
支持插件定制:OpenVAS扫描器支持定制插件,用户可以使用Nessus Attack Scripting Language (NASL)编写插件。认证扫描:在认证扫描时,用户提供目标机的登录凭证,扫描器可以登录,并扫描主机上安装的组件的漏洞(Adobe reader、Wireshark等)导出报告:OpenVAS有多个选项来导出报告。用户可以以HTML、XML、TXT和PDF的格式生成和下载报告。端口扫描:OpenVAS有多个选项进行端口扫描。包括TCP scan, SYN scan, IKE-scan,来定位IPSec, VPN等.安全检查:OpenVAS支持安全地扫描。在这个模式下,scanner会依据远程主机的banner来发送载荷,而不是发送所有的载荷。这个选项对于重要的和陈旧的主机很有用,可以防止在扫描时崩溃
部署过程 #安装依赖包 [root@docker-server2 ~]# yum install -y wget bzip2 texlive net-tools alien gnutls-utils #添加OpenVAS的仓库 [root@docker-server2 ~]# wget -q -O - https://www.atomicorp.com/installers/atomic | sh #安装 [root@docker-server2 ~]# rpm -ivh atomic-release-1.0-23.el7.art.noarch.rpm 准备中... ################################# [100%] 软件包 atomic-release-1.0-23.el7.art.noarch 已经安装 #安装openvas [root@docker-server2 ~]# yum -y install openvas #部署 [root@docker-server2 ~]# openvas-setup 这里默认rsync
背景 时间点:2023年03月
场景:做一个通用型的多种证件解析服务
需求:调研一种又新又快的定位模型。要求:1)支持倾斜的文字,可以是4点定位或分割法后获取box,但不能是2点的定位;2)快速,过往的psenet需要至少0.6s,pan和db在一些场景中效果差一点但快,是否有更好平衡速度和效果的方法;3)方便改输出通道数量,这种一般是分割?;4)边缘准确;5)适用于中文大字典
方法:从3个方法研究,pp、mmocr、papers with code
调研 PP https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.6/doc/doc_ch/PP-OCRv3_introduction.md
assert alg in [ 'EAST', 'DB', 'SAST', 'Rosetta', 'CRNN', 'STARNet', 'RARE', 'SRN', 'CLS', 'PGNet', 'Distillation', 'NRTR', 'TableAttn', 'SAR', 'PSE', 'SEED', 'SDMGR', 'LayoutXLM', 'LayoutLM', 'LayoutLMv2', 'PREN', 'FCE', 'SVTR', 'ViTSTR', 'ABINet', 'DB++', 'TableMaster', 'SPIN', 'VisionLAN', 'Gestalt', 'SLANet', 'RobustScanner', 'CT', 'RFL', 'DRRG', 'CAN', 'Telescope' ] PP-OCRv3检测模块仍基于DB算法优化,而识别模块不再采用CRNN,换成了IJCAI 2022最新收录的文本识别算法SVTR
mmocr https://gitee.com/open-mmlab/mmocr#%E6%A8%A1%E5%9E%8B%E5%BA%93
最新的检测识别是dbnet++、SVTR
papers with code 从ppocr和mmocr看到,2者选择的方案都是dbnet++及SVTR,dbnet++是2022年的算法。在paperswithcode中,不是特别高的排名,有个疑问,为啥最后会选用这个呢?出于速度考虑???
https://paperswithcode.com/paper/real-time-scene-text-detection-with-1
目前考虑的方法
DPText-DETR,排名最高,后续试了效果还不错,感动,哪怕是有600多切片的图片,速度也在0.1-0.2s
FAST-B-800,排名2
DBNet++ 商业化落地最多的
排除的方法
TextFuseNet不适合中文
1. Mybatis基础操作 1.1 需求 需求说明:
根据资料中提供的《tlias智能学习辅助系统》页面原型及需求,完成员工管理的需求开发。 通过分析以上的页面原型和需求,我们确定了功能列表:
查询
根据主键ID查询条件查询 新增
更新
删除
根据主键ID删除根据主键ID批量删除 1.2 准备 实施前的准备工作:
准备数据库表创建一个新的springboot工程,选择引入对应的起步依赖(mybatis、mysql驱动、lombok)application.properties中引入数据库连接信息创建对应的实体类 Emp(实体类属性采用驼峰命名)准备Mapper接口 EmpMapper 准备数据库表
-- 部门管理 create table dept ( id int unsigned primary key auto_increment comment '主键ID', name varchar(10) not null unique comment '部门名称', create_time datetime not null comment '创建时间', update_time datetime not null comment '修改时间' ) comment '部门表'; -- 部门表测试数据 insert into dept (id, name, create_time, update_time) values (1, '学工部', now(), now()), (2, '教研部', now(), now()), (3, '咨询部', now(), now()), (4, '就业部', now(), now()), (5, '人事部', now(), now()); -- 员工管理 create table emp ( id int unsigned primary key auto_increment comment 'ID', username varchar(20) not null unique comment '用户名', password varchar(32) default '123456' comment '密码', name varchar(10) not null comment '姓名', gender tinyint unsigned not null comment '性别, 说明: 1 男, 2 女', image varchar(300) comment '图像', job tinyint unsigned comment '职位, 说明: 1 班主任,2 讲师, 3 学工主管, 4 教研主管, 5 咨询师', entrydate date comment '入职时间', dept_id int unsigned comment '部门ID', create_time datetime not null comment '创建时间', update_time datetime not null comment '修改时间' ) comment '员工表'; -- 员工表测试数据 INSERT INTO emp (id, username, password, name, gender, image, job, entrydate, dept_id, create_time, update_time) VALUES (1, 'jinyong', '123456', '金庸', 1, '1.
提醒:以下内容仅做参考,可自行发散。在发布作品前,请把不需要的内容删掉。
无论是初学者还是有经验的专业人士,在学习一门新的IT技术时,都需要采取一种系统性的学习方法。那么作为一名技术er,你是如何系统的学习it技术的呢。
一、明确学习目标 在学习Python深度学习之前,需要明确自己的学习目标。例如,你可能想学习如何使用Python实现深度神经网络,或者想学习如何使用Python进行自然语言处理等。
二、寻找学习资源 一旦明确了学习目标,就需要寻找相关的学习资源。对于Python深度学习,可以选择一些优秀的书籍、教程、视频和在线课程。例如,可以选择《Python深度学习》一书,或者在Coursera上学习斯坦福大学的《深度学习》课程。
三、制定学习计划 在选择了学习资源后,需要制定学习计划。这包括安排学习时间、制定每天、每周的学习计划,并设定学习目标和截止日期。例如,可以制定每天学习1小时,每周完成1个项目的计划。
四、深入理解基础概念 在学习Python深度学习时,需要深入理解基础概念。这包括Python编程语言的语法、深度神经网络的原理、常用的深度学习框架(例如TensorFlow、PyTorch等)等。只有深入理解基础概念,才能更好地掌握技术。
五、实践和应用 在学习Python深度学习时,需要不断地实践和应用。例如,可以使用Python实现一个简单的深度神经网络,并使用该网络进行图像分类或者文本分类等任务。通过实践和应用,可以更好地掌握技术,并且在实践中发现和解决问题。
六、参与社区 参与Python深度学习社区可以帮助你更好地学习和成长。你可以加入Python论坛、参加Python深度学习交流会、关注Python深度学习博客等。通过与其他人交流,你可以了解最新的技术趋势和最佳实践,同时也可以结交志同道合的朋友。
七、持续学习 Python深度学习是一个不断发展和变化的领域,因此持续学习非常重要。你需要不断地学习新技术、新工具和新解决方案,以保持自己的竞争力。例如,学习如何使用Python进行自然语言生成、如何使用Python进行图像生成等。
总结:学习Python深度学习需要明确学习目标、寻找学习资源、制定学习计划、深入理解基础概念、实践和应用、参与社区和持续学习。只有通过不断的学习和实践,才能学好你想要深耕的IT技术。
文章目录 何为点云获取点云数据的渠道点云的应用范围Advantages & Difficulties深度学习方法介绍 何为点云 N ✖ 3 matrix or N ✖ (3 + D) matrix
即一个n*3的矩阵,以及额外的信息包括颜色、法向量之类。
获取点云数据的渠道 激光雷达RGB-D相机:一种可以同时获取彩色图像和深度信息的相机。它通过结合红外线投影和红外线摄像头,能够获取场景中每个像素点的深度信息,并将其与彩色图像进行配对,从而实现三维重建和物体识别等应用CAD模型SfM(Sturcture-from-Motion)Depth from Images 点云的应用范围 机器人领域自动驾驶领域手机人脸识别(iphone的深度摄像头可以通过点云获取人脸信息,识别的精度和安全性更高) Advantages & Difficulties 用uber来举例如何将velodyne 64线雷达应用在uber无人车上的话
首先是障碍物检测环节,前景的点(Orange points)被分离出来后使用特定的聚类算法(Clustering),将障碍物区分成一个个独立的个体(车,路障等等),这里就需要用到语义分割算法。之后车辆被标记成了不同的颜色,并使用模型拟合算法将车辆拟合成一个多边形。
例如uber会用到flann的库来进行点云的最邻近搜索。
激光雷达作为感知的源头需要搭载在车身上进行标定。下图是uber的标定工作,将车辆放在可360度旋转的平台上,进行图片角点检测。激光雷达和摄像头检测到平面的位置后,再计算出两者之间的相对位置。
然后是三维拟合
比如Mesh使用三角形拟合三维物体,在图形学里很好用,但是在机器人和计算机视觉领域就不那么好用,因为描述三角形往往比描述一个点要复杂。
然后就是voxel grid,这种形式很简单但并不高效,因为我们三维世界大部分空间是空的,会有内存浪费的问题。
然后就是octree(二叉树),他解决了效率的问题
最后就是点云,但点云的一些特性也使它难以处理。
Sparsity,密度问题尤其是在激光雷达里面,点云会随着距离逐渐稀疏,比如说百米以外一个车,反射回来不到十个点,就使得这辆车很难识别。
Irregular-difficulty in neighbor searching,另一个问题就是不规则。例如,图像的每一个像素都是排列规整的网格,如果我们要找一个像素的邻居,只需要上下左右一格就好,但是我们很难找到点云最近的一个指定范围半径的点。
Un-ordered-difficulty in deep learning,纹理信息,就会形成当三个人并排走在一起时,就会被识别成一辆车,在缺乏纹理信息时,三人站成一个人桥跟一辆车背面的宽度是差不多的。
如上面的矩阵所示,第一行和第二行被交换,最后N行被k行替代,但不管这些行如何交换,它们表达的都是同一个物体,对于深度学习而言,输入的矩阵不同,但是我们希望输出是一样,这就是深度学习中unorder的问题。
Rotation equivariance / invariance
深度学习方法介绍 当下的点云处理包含传统方法和前沿方法(深度学习)
Classical Methods Explainable - It follows physics and we know why it works/doesn’t
workControtable - We know how to debug Deep learning Methods SimpleHigh performanceData driven 传统方法是可控且精准的,我们可以用数学去精准描述这些方法如何实现,有什么可预期的输出。而深度学习就像一个黑盒子,我们不知道他是如何工作的,甚至也无法控制它去怎么工作,好处就是他非常简单,人人可用。
目录
一、MySQL数据模型
二、SQL概述
1.SQL简介
2.通用语法
3.SQL分类
4.DDL--操作数据库
5.DDL-操作表
6.DML:对数据进行增(insert)删(delete)改(update)操作
7.DQL-查询操作
前言: 1.1 数据库 存储和管理数据的仓库,数据是有组织的进行存储。 数据库英文名是 DataBase ,简称 DB 。 数据库就是将数据存储在硬盘上,可以达到持久化存储的效果。那又是如何解决上述问题的?使用数据库管理系统。 1.2 数据库管理系统 管理数据库的大型软件 英文: DataBase Management System ,简称 DBMS 在电脑上安装了数据库管理系统后,就可以通过数据库管理系统创建数据库来存储数据,也可以通过该系统对数据库中的数 据进行数据的增删改查相关的操作。 注意:我们平时说的MySQL 数据库其实是 MySQL 数据库管理系统。 一、MySQL数据模型 关系型数据库是建立在关系模型基础上的数据库,简单说,关系型数据库是由多张能互相连接的二维表组成的数据库。
数据模型:
如上图,我们通过客户端可以通过数据库管理系统创建数据库,在数据库中创建表,在表中添加数据。创建的每一个数据库对应到磁盘上都是一个文件夹。 比如可以通过SQL 语句创建一个数据库(数据库名称为 db1),语句如下。 create database db1; 我们可以在数据库安装目录下的 data 目录下看到多了一个 db1 的文件夹。所以, 在MySQL中一个数据库对应到磁盘上的一 个文件夹 。 而一个数据库下可以创建多张表,我们到MySQL 中自带的 mysql 数据库的文件夹目录下: 而上图中右边的 db.frm 是表文件,db.MYD 是数据文件 ,通过这两个文件就可以查询到数据展示成二维表的效果。 总结: MySQL中可以创建多个数据库,每个数据库对应到磁盘上的一个文件夹 在每个数据库中可以创建多个表,每张都对应到磁盘上一个 frm 文件 每张表可以存储多条数据,数据会被存储到磁盘中 MYD 文件中 二、SQL概述 1.
目录
一、JDBC概念
1.1Java操作数据库的流程
1.2编写代码步骤
1.3具体操作
二、JDBC API详解
2.1 DriverManager(驱动管理类) 作用
2.2 Connection(数据库连接对象)作用:
2.3 Statement 2.4 ResultSet (结果对象集)作用
2.5 PreparedStatement 三、数据库连接池实现
一、JDBC概念 JDBC 就是使用 Java语言操作关系型数据库的一套API,全称(Java DataBase Connectivity) java数据库连接; 1.1Java操作数据库的流程 第一步:编写Java代码 第二步:Java代码将SQL发送到MySQL服务端 第三步:MySQL服务端接收到SQL语句并执行该SQL语句 第四步:将SQL语句执行的结果返回给Java代码 1.2编写代码步骤 创建工程,导入驱动jar包注册驱动获取连接定义SQL语句获取执行SQL对象执行SQL处理返回结果释放资源 1.3具体操作 1.3.1 创建新的空的项目 1.3.2定义项目的名称,并指定位置 1.3.3 对项目进行设置,JDK版本,编译版本 1.3.4 创建模块,指定模块的名称及位置 1.3.5 导入驱动包 将mysql的驱动包放在模块下的lib(自己创建并命名的文件夹)目录下,并将该jar添加为库文件。
驱动包的下载:
1.打开 MySQL 官网:https://www.mysql.com/ mysql官网2.点击 downloads,把页面滚动到最下面,点击 MySQL Community (GPL) Downloads3.点击 Connector/J4.点击 General Availability(GA) Releases,在 Select Operating System 下拉列表选择 Platform Independ 注意在添加库文件时有三个选项:
Global Library : 全局有效 Project Library : 项目有效 Module Library : 模块有效 根据自己的需求进行选择,这里我选择的是模块有效
1.vuex存储在内存,localstorage则以文件的方式存储在本地
2.vuex用于组件之间的传值,localstorage则主要用于不同页面之间的传值
3.当刷新页面时vuex存储的值会丢失,localstorage不会
备注:很多伙伴觉得用localstorage可以代替vuex, 对于不变的数据确实可以,但是当两个组件共用一个数据源(对象或数组)时,如果其中一个组件改变了该数据源,希望另一个组件响应该变化时,localstorage无法做到
1、router.js路由内部写法
// 将vueRouter设置为vue的插件 Vue.use(VueRouter) const router = new VueRouter({ // 指定hash属性与组件的对应关系 routes: [ { path: '/', component:institution }, { path: '/login', component:login }, { path: '/register', component:register }, { path: '/forget', component:forget }, { path: '/home', component:home, meta:{auth: true}},//添加字段判断该页面是否需要登录 { path: '/tips', component:tips, meta:{auth: true}}, { path: '/consult', component:consult, meta:{auth: false}} ] }) // 路由守卫 router.beforeEach((to,from,next)=>{ // to要跳转到的路径 // from从哪个路径来 // next往下执行的回调 // 在localStorage中获取token let token=localStorage.getItem('userName') // 判断该页面是否需要登录 if(to.meta.auth){ // 如果token存在直接跳转 if(token){ next() }else{ // 否则跳转到login登录页面 next({ path:'/login', // 跳转时传递参数到登录页面,以便登录后可以跳转到对应页面 query:{ redirect:to.
目录
项目搭建选项
项目搭建步骤
本地开发环境
Vite脚手架构建项目
关联Git仓库
开发工具
安装pinia
安装Sass
安装Vant-UI
安装postcss-pxtorem(移动端项目)
安装axios
本地调试
环境变量
本地代理
全局UI组件
路由中间件
项目部署
nginx配置
jenkins自动化部署
自由风格配置
流水线配置
灰度部署方案
项目搭建选项 Vue3ViteTypeScriptaxiosPiniaSassVant-UI(M)、Element-UI(PC)Eslintpostcss-pxtorem(M) 项目搭建步骤 本地开发环境 安装nodejs,node版本建议大于16.0.0
Download | Node.js
Vite脚手架构建项目 官网:https://cn.vitejs.dev/guide/
关联Git仓库 初始化后的项目关联远程git仓库
开发工具 Visual Studio Code
配置.vscode/setting.json,自动校验eslint并修复
{ // 开启保存自动格式化 "editor.formatOnSave": true, // 开启eslint校验 "eslint.enable": true, "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"], "editor.fontSize": 14, // vscode默认启用了根据文件类型自动设置tabsize的选项 "editor.detectIndentation": false, // 重新设定tabsize "editor.tabSize": 2, // #每次保存的时候将代码按eslint格式进行修复 "editor.codeActionsOnSave": { "source.fixAll.eslint": true }, // 校验文件类型 "
背景:MySQL自动化分区现阶段只支持datetime类型,需要添加数字类时间戳类型,用于zabbix的history历史表数据自动化分区。
1.zibbix的历史表结构 CREATE TABLE `history` ( `itemid` bigint(20) unsigned NOT NULL, `clock` int(11) NOT NULL DEFAULT '0', `value` double NOT NULL DEFAULT '0', `ns` int(11) NOT NULL DEFAULT '0', KEY `history_1` (`itemid`,`clock`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin 2.修改存储过程部分 partition_maintenance DELIMITER $$ USE `managerdb`$$ DROP PROCEDURE IF EXISTS `partition_maintenance`$$ CREATE DEFINER=`root`@`%` PROCEDURE `partition_maintenance`(p_schema_name VARCHAR(32), p_table_name VARCHAR(32), p_keep_data_days INT, p_create_next_intervals INT,p_par_column VARCHAR(64)) BEGIN /* */ DECLARE l_older_than_partition_date VARCHAR(16); DECLARE l_partition_name VARCHAR(16); DECLARE l_old_partition_name VARCHAR(16); DECLARE l_less_than_timestamp DATETIME; DECLARE l_cur_time VARCHAR(64); DECLARE l_partition_type VARCHAR(16); -- 数字时间戳新增 -- 检查分区字段类型 SELECT data_type INTO l_partition_type FROM information_schema.
软硬连接 在linux下面链接文件有两种,一种是类似window的快捷方式功能的文件,可以让你快速链接到目标文件(或目录),叫做软链接,另一种则是通过文件系统的inode链接来产生新的文件名,而不是产生新的文件,这种叫做硬链接。这是完全不一样的东西。
1.软链接(symbolic link也叫符号链接) 软链接是一个独立的链接文件,有自己的inode,也有自己的inode属性和内容,内部放的是自己所指向的文件的路径,当被链接的原文件出现问题后,该链接则不能使用。
创建命令 ln -s 目标文件 新的链接文件名(自定义的)
示例: 与文件建立软链接
与目录建立软链接
软链接可运用的地方:将一个路径很深的程序,或者库,或者对应的头文件,建立到当前目录下,或者是很好找的路径下,让我们快速去访问到这个文件。
2.硬链接(hard link) 硬链接和目标文件共用一个inode,不会创建新文件,当我们添加一个硬链接时,只更改了当前目录的内容:在目录中增加了新的文件名,添加了原文件的inode和文件名的映射关系。而这个映射关系有一个计数,每多一个硬链接,这个链接数就会+1,这是创建的时候,当我们要删除文件的时候也是,只有等这个连接数为0时,这个文件才算真正意义上的被删除。在没完全删除之前我们都可以通过该文件的其他硬链接来进行访问。(我们其实可以将硬链接当做一个浅拷贝的过程,也就是多增加一个指针指向同一个文件)
红圈出来的数代表硬链接数 创建命令
ln 目标文件 新的链接文件名(自定义的)
与文件建立硬链接
无法与目录建立硬链接
3.解除软硬链接 unlink 软链接名/硬链接名
为什么新建的文件夹硬链接数是2呢?
因为文件夹名和inode构成一组映射关系,而文件夹里面的隐藏文件 . 其实是文件夹的硬链接 4.不能给目录建立硬链接 但是我们上面也说了目录中的一个点(.)代表的其实是文件夹的硬链接,代表当前路径,这又是怎么回事呢?
原来操作系统只允许自己给目录建立硬链接,不允许用户创建,是为了避免环路问题。 举个栗子(假设真的能给目录建立硬链接)
我们都知道目录文件(文件夹)实际上是一种多叉树结构,在目录中找到其他的文件夹名即可用cd 文件夹名进行访问(图中红箭头),也可以cd .. 返回到上级目录(图中蓝箭头),现在我们在d3目录下建立一个d2的硬链接,再创建一个test.c文件,现在要用find命令从d1目录下开始递归式查找test.c文件,但是当我们进入d3的时候遇到hard-link时,又会回到d2里重新找,这样循环往复就出不来了。
再举一个详细的栗子
如果使用hard link链接到目录时,链接的数据需要连同被连接目录下面的所有数据都建立链接,就是说如果你要将/etc使用硬链接来创建一个/etc_hd目录时,那么在/etc_hd目录下面的所有文件名同时都与/etc下面的文件名要创建硬链接,没那么简单,并且,未来如果在/etc_hd下面创建新文件时,连带的,/etc下面的数据又得要创建一次hard link,过于复杂,所以hard link目前对于目录来说暂时不支持。
但是隐藏文件 . 和 .. 又这么解释呢?
它们不也会构成环路问题,这个其实是操作系统进行维护的,而且链接的路径不深。只需要操作系统进行特殊处理就行,但是如果也允许用户这样搞的话,有可能链接的路径很深,这样比如在执行查找或者路径切换的时候就会出问题。
5.总结: 硬链接
1.不能跨文件系统
2.不允许给目录创建硬链接
3.只有当硬链接数为0时,该文件才会完全删除。
4.创建只是在某个目录下添加文件名,以及inode和文件名的映射关系(链接数+1)
软链接
1.可以跨文件系统
2.允许给文件创建软链接
3.是一个独立的文件,有自己的inode,会占用block
4.链接文件被删除,该链接也没有用了
补充: stat 文件名
显示文件的三个时间
access 最后访问时间
modify 文件内容最后修改时间
解决办法:在python路径下的Lib中新建一个fcntl.py文件内容如下:
Traceback (most recent call last): File "C:\Users\admin\miniconda3\envs\index\lib\runpy.py", line 196, in _run_module_as_main return _run_code(code, main_globals, None, File "C:\Users\admin\miniconda3\envs\index\lib\runpy.py", line 86, in _run_code exec(code, run_globals) File "C:\Users\admin\miniconda3\envs\index\Scripts\gunicorn.exe\__main__.py", line 4, in <module> File "C:\Users\admin\miniconda3\envs\index\lib\site-packages\gunicorn\app\wsgiapp.py", line 9, in <module> from gunicorn.app.base import Application File "C:\Users\admin\miniconda3\envs\index\lib\site-packages\gunicorn\app\base.py", line 11, in <module> from gunicorn import util File "C:\Users\admin\miniconda3\envs\index\lib\site-packages\gunicorn\util.py", line 8, in <module> import fcntl ModuleNotFoundError: No module named 'fcntl' 提示我C:\Users\admin\miniconda3\envs\index环境下没有,那就在这个环境下捏一个fcntl.py新文件
新建完了,将下面内容写进去保存好
def fcntl(fd, op, arg=0): return 0 def ioctl(fd, op, arg=0, mutable_flag=True): if mutable_flag: return 0 else: return "
app热更新是app项目最常见的功能,接下来我总结了当时做这个功能的过程,来交流学习一哈
热更新的流程步骤 在用户进入app就获取当前版本号与调用后端接口返回的版本号对比是否是最新的版本不是最新弹出弹窗让用户确认是否更新,点击更新下载wgt资源包更新,重启应用即可
代码流程 1.封装两个判断js文件 call-check-version.js 判断是否需要更新 import { getVersion } from '@/api/user.js' // 获取最新版本信息的接口 /** * 对比版本号,如需要,请自行修改判断规则 * 支持比对 ("3.0.0.0.0.1.0.1", "3.0.0.0.0.1") ("3.0.0.1", "3.0") ("3.1.1", "3.1.1.1") 之类的 * @param {Object} v1 * @param {Object} v2 * v1 > v2 return 1 * v1 < v2 return -1 * v1 == v2 return 0 */ function compare(v1 = '0', v2 = '0') { v1 = String(v1).split('.') v2 = String(v2).split('.') const minVersionLens = Math.
背景 在访问vue系统时,经常需要在进入路由前做一些全局处理或者登录状态校验,如果全部写在beforeEach函数中,内容会特别多,难以维护。需要将beforeEach中的内容拆分成多个中间件方法,按顺序执行。
步骤 1、注册中间件 注册需要的中间件文件,以修改页面标题和登录校验为例
router / middlewares / changeTitle.ts
export default async ({ to, next }: any) => { if (to.meta?.title) { // 修改页面title document.title = to.meta.title } next() } router / middlewares / auth.ts
export default async ({ to, next }: any) => { // 需要登录才能访问的页面path const needLoginPath = ['/about', '/orders', '/my-account'] if (needLoginPath.includes(to.path) && !localStorage.getItem('token')) { // 访问需要登录的页面,并且没有登录状态,跳转登录页 next('/login') } else { next() } } 2、新建路由中间件执行文件 router / middlewarePipeLine.
文章目录 开门见山控制台程序 开门见山 方法一、运行程序的时不用F5键执行,用Ctrl+F5执行,它的意思是“启动执行(不调试)”。
方法二(推荐)、在你的代码的最后加上这句 Console.ReadLine();
也就是“等待用户输入”,这样DOS窗口直到你敲击回车键才会关闭或者在程序最后加上一句Console.ReadKey();这样DOS窗口接收一个字符才会退出。
方法三、在CMD下运行程序。
控制台程序 以下源自百度百科:
控制台程序是为了兼容DOS程序而设立的,这种程序的执行就好像在一个DOS窗口中执行一样,没有自己的界面。
所谓的控制台应用程序,就是能够运行在MS-DOS环境中的程序。控制台应用程序通常没有可视化的界面,只是通过字符串来显示或者监控程序。控制台程序常常被应用在测试、监控等用途,用户往往只关心数据,不在乎界面。
控制台程序是为了兼容DOS程序而设立的,这种程序的执行就好像在一个DOS窗口中执行一样,没有自己的界面。
INTEL的CPU有三种工作模式,实模式,保护模式,虚拟模式。实模式是16位的,在这种模式下可工作纯DOS。保护模式是32位的,WINDOWS就工作在这种模式下,为了使在32位保护模式下工作的WINDOWS可兼容16位实模式下的DOS程序,又设立了虚拟模式,就是控制台程序。
没有粉丝,没有评论,甚至连读者都没有。因为自己写的烂,因为自己水平有限,所以自己的作品一经发出就石沉大海了,得不到任何的回信,就好像自己写的东西是给自己看的。自己的作品怎么看都好像不够完美,全身的毛病,所以读者不喜欢也很正常对吧!
其实最让我开心的是有些读者们夸我文笔不错,或许是有人第一次这样夸我的缘故吧!又或许是我写的东西没什么人认可,我感受到了一种前所未有的激动,对于未来的憧憬,对自己写下去的动力。
因为有你们,我的写作之路才不孤独,因为有你们,我才能坚持到现在,如果有一天我真的写出圈了,或许我们可以整个交流会之类的,到时候促膝长谈。
“书山有路勤为径,学海无涯苦作舟。”写作苦是苦了点,整得我差点就想放弃了,不过还好有你们。我也不急着成功,因为没有个几十年如一日的坚持,哪能轻易成功?
茫茫文海无人意,天下有君识吾心。文海很孤独,但是有诸君,便足以令我至千里。
selenium模拟登陆 思路代码结果图 思路 使用selenium去模拟登陆比发送请求的方式更简单,所以本文采用selenium自动化模拟登陆,智慧南工(南京工业大学校园内网登陆验证界面)在更新过后,加入了验证码验证,故本文使用了深度学习的PaddleOCR进行验证码识别,识别准确率在百分之八十左右,作者在后期也会进行验证码图像处理,增加准确率。
而验证码识别思路,我提供两个:1.Tesseract识别pytesseract 2.深度学习网络识别。作者前期使用了第一个思路进行识别,但发现识别效果超级差,故改用了飞桨的OCR模型。
对于验证码的保存也有两种思路:1.找到验证码链接,直接使用request请求下载图片2.使用selenium的屏幕截图,并通过定位验证码的坐标和大小,后期截取验证码(需注意电脑默认的缩放比)。
仅供学习!!!
代码 由于实现过程较简单,故直接上代码了,selenium的环境什么的需要自己去配置。
from selenium import webdriver import time import cv2 as cv import numpy as np from selenium.webdriver.common.by import By import pytesseract from PIL import Image from selenium.webdriver.support.wait import WebDriverWait from selenium.common.exceptions import TimeoutException from paddleocr import PaddleOCR import operator class login: def __init__(self,account,passward) : self.account=account self.passward=passward self.url="https://u.njtech.edu.cn/cas/login?service=https%3A%2F%2Fu.njtech.edu.cn%2Foauth2%2Fauthorize%3Fclient_id%3DOe7wtp9CAMW0FVygUasZ%26response_type%3Dcode%26state%3Dnjtech%26s%3Df682b396da8eb53db80bb072f5745232" print("自动化登陆开始!") # self.header={"User-Agent":" Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.
1、创建应用代开发模版 1.1、登录企业微信服务商后台管理,进入应用管理->应用代开发 页面,创建模版;
填写模版相关参数:
回调地址,用于模版事件回调
模版创建提交时,微信平台会发送验证信息到此地址,验证是否有效;
企业管理员扫模版的授权二维码时,发送的授权通知会调用此地址;
token
用于验证回调信息和事件信息内容中的签名是否有效
EncodingAESKey
用于模版回调事件中的信息内容的解密,模版应用后端主动发送信息到微信平台时消息的加密也使用到
1.2、模版创建完成后,模版就有了相关参数
1.3、接收推送的suite_ticket
在模版回调地址里,要有接收suite_ticket的处理逻辑,企业微信服务器会定时(每十分钟)推送ticket,
若开发者想立即获得ticket推送值,可以点击上面的模版信息里的 【刷新ticket】按钮,将直接触发推送事件;
开发人员在后端,要把每次推送过来的ticket记录到数据库或文件中。
(用于获取第三方应用凭证 suite_access_token,suite_access_token 在模版获取企业永久授权码时使用,企业永久授权码 就是 代开发应用的 secret )
2、模版上线审核 审核完成后,模版会生成授权二维码
3、客户企业微信管理员授权 将模版的授权二维码发给客户企业微信的管理员,管理员扫码完成授权,这时,模版详情页面,就会显示授权企业客户和代开发应用。
4、代开发应用配置 点击 模版详情页面显示的 代开发应用列表里的代开发应用,配置代开发应用 , 点击应用secret【重新获取】,微信平台会发送重新获取secret的事件到代开发应用回调地址,开发人员要在接收事件后,调用获取企业永久授权码API,取到授权企业微信的ID、永久授权码(就是密钥)、授权应用ID,把这三个参数配置到我们程序里。
注意:回调可信域名要与回调地址域名一致,域名前没有www的,这边配置的可信域名也不能有www前缀
主要配置为:
权限设置,编辑配置后,需要企业管理员授权确认才有效应用主页地址可信域名 5、上线代开发应用 提交代开发应用上线审核,审核通过后,提交应用上线。
Java 数组是一种非常有用的数据结构,它用于存储相同类型的元素,并且可以通过下标访问。在本文中,我们将介绍 Java 数组的使用,包括如何声明、创建、初始化和使用数组。
一、声明和创建数组 在 Java 中,要声明和创建数组,需要使用相同的数据类型,并使用方括号 [] 括起来。要创建数组,需要在方括号中指定数组的长度。例如,以下代码声明并创建了一个包含 5 个整数的数组:
int[] myArray = new int[5]; 在这个例子中,我们声明了一个名为 myArray 的 int 类型数组,数组的长度为 5。
二、初始化数组 在声明和创建数组之后,需要初始化数组中的元素。可以使用以下几种方式初始化数组:
使用花括号 {} 初始化数组 可以使用花括号初始化数组,这种方式可以在声明数组时同时进行初始化。例如,以下代码创建并初始化了包含 5 个整数的数组:
int[] myArray = {1, 2, 3, 4, 5}; 在这个例子中,我们创建了一个名为 myArray 的 int 类型数组,并使用花括号初始化了数组中的元素。
使用循环初始化数组 可以使用循环初始化数组,这种方式可以在程序运行时动态地设置数组中的元素。例如,以下代码使用循环创建并初始化了包含 5 个整数的数组:
int[] myArray = new int[5]; for (int i = 0; i < myArray.length; i++) { myArray[i] = i + 1; } 在这个例子中,我们创建了一个名为 myArray 的 int 类型数组,并使用循环初始化了数组中的元素。
系列文章目录 提示:这里是该系列文章的所有文章的目录
第一章: Qt连接Sqlite3并使用Qtableview实时显示数据,重写QSqlQueryModel实现文本居中
第二章: Qt下使用Sqlite数据库实现图片的读写显示
文章目录 系列文章目录前言一、引入SQL模块二、数据库的基本操作三、示例完整代码四、下载链接总结 前言 什么是 SQLite?
SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库不一样,您不需要在系统中配置。(来自菜鸟教程SQLite简介)
在我以前的文章有介绍Qt下MySQL数据库的使用,需要进行MySQL服务器的连接,有时候还需要编译Qt源码来获取MySQL驱动,使用起来有点麻烦。如果我们的项目不需要一个单独的服务器进程或操作的系统(无服务器的),这时候可以选择使用SQLite数据库来保存数据,这里介绍一下Qt中自带驱动的Sqlite3数据库的使用,并结合相应的示例进行讲解,标题功能的体现见示例完整代码,如有错误之处,欢迎大家批评指正。
项目效果
提示:以下是本篇文章正文内容,下面案例可供参考
一、引入SQL模块 在Qt项目文件(.pro文件)中,加入SQL模块:
QT += sql 有的pro中是有“Qt += core gui”的,可以直接加在这后面:
QT += core gui sql 添加头文件
#include <QSqlQuery> #include <QSqlError> #include <QSqlDatabase> #include <QSqlQueryModel> 二、数据库的基本操作 1.在指定保存路径下以当天日期为名称创建数据库并打开
QString dbPath = QCoreApplication::applicationDirPath() + "/SaveDbFile/"; QString dbName = dbPath + QDate::currentDate().toString("yyyyMMdd") + ".db"; m_db = QSqlDatabase::addDatabase("QSQLITE"); m_db.setDatabaseName(dbName); if(!m_db.open()) { //打开失败打印 qDebug()<<"数据库打开失败..."<<m_db.lastError(); } 2.创建名为dataTable的数据表
QSqlQuery query(m_db); QString createStr = "
目录
MySQL
连接查询
表
约束
存储引擎
事务
索引
视图(View)
数据库的导入导出(DBA命令)
数据库设计三范式
MySQL sql、DB、DBMS分别是什么?它们之间的关系?
DB:
DataBase(数据库,实际上在硬盘以上以文件的形式存在)
DBMS:
DataBase Management System(数据库管理系统,常见的有:MySQL Oracle DB2 SqlServer…)
SQL:
结构化查询语言,是一门标准通用的语言。标准的sql适合于所有的数据库产品。
SQL属于高级语言,只要能看懂英语单词,都可以看懂sql语句是什么意思
SQL语句在执行的时候,实际上内部也会先进行编译,然后再执行sql。(sql的编译由DBMS完成)
DBMS负责执行sql语句,通过执行sql语句来操作DB当中的数据
DBMS—(执行)—>SQL—(操作)—>DB
什么是表?
表:table。
表table是数据库的基本组成单元,所有数据都以表格的形式组成,目的是可读性强
学号(int) 姓名(varchar) 年龄(int) ---------------------------------------- 110 张三 20 120 李四 21 每一个字段应该包括哪些类型?
字段名、数据类型、相关的约束
学习MySQL主要还是学习通用的SQL语句,那么SQL语句包括增删改查,SQL语句怎么分类呢?
DQL(数据查询语言):查询语言,凡是select语句都是DQLDML(数据操作语言):insert、delete、update,对表当中的数据进行增删改查DDL(数据定义语言):create、drop、alter,对表结构的增删改TCL(事务控制语言):commit提交事务,rollback回滚事务。(TCL中的T是Transaction)DCL(数据控制语言):grant授权、revoke撤销权限等 导入数据
第一步:登录mysql数据库管理系统。
dos命令窗口:mysql -uroot -p123
第二步:查看有哪些数据库
show databases;(这个不是SQL语句,属于MySQL的命令)
+--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ 第三步:创建属于我们自己的数据库
本节的目的不在于去教大家理解docker容器(讲docker就脱离了我们课程的核心,我们的课程是Spring Boot 不是docker),而是希望通过docker的方式快速的为大家搭建一个redis数据库,从而方便大家学习使用,方便学习本章后续的内容。如果你想学好docker,你应该再去学另外的课程。
如果你觉得docker安装redis对于你来说有困难,可以下载一个windows版本的redis安装,达到可以开始后续章节学习的目的即可。
准备工作 首先要安装好docker。CentOS7如何安装docker方法在本文档的番外篇里面介绍 下面的安装过程如果看不懂,回头来看这个图理解一下。
一、获取 redis 镜像 如果你不熟悉docker,可以认为docker镜像是安装包。
docker search redis docker pull redis:5.0.5 docker images 其实更形象点的理解docker镜像和容器之间的关系,更像是Class类与对象之间的关系。一个类可以构造多个对象,一个镜像可以构造多个容器。类和镜像是实实在在存在的字节码文件;对象和容器是在系统内存里面,作为运行时状态存在。
二、创建容器 2.1.创建持久化存储目录 容器可以运行在内存里面,但是容器存储的数据需要进行持久化。所以在宿主机上创建redis 容器的数据和配置文件存储目录。
# 这里我们在 /home/docker 下创建 mkdir /home/docker/redis/{conf,data} -p cd /home/docker/redis 注意:后面所有的操作命令都要在这个目录/home/docker/redis下进行
2.2.获取 redis 的默认配置文件模版 # 获取 redis 的默认配置模版 # 这里主要是想设置下 redis 的 log / password / appendonly # redis 的 docker 运行参数提供了 --appendonly yes 但没 password wget https://gitee.com/hanxt/boot-launch/raw/master/src/main/resources/otherconfig/redis.conf -O conf/redis.conf # 直接替换编辑 sed -i 's/logfile ""/logfile "
问题的场景是 当前端调用后端接口时,如果后台返回的ID值比较大(例如雪花算法生成的ID),在JavaScript中处理的时候会出现精度丢失的问题。为解决这个问题,可以将ID转化为字符串类型,也可以通过前端框架或组件库进行处理。
解决这个问题,有以下几种思路:
将后端返回的 ID 值转化为字符串类型。这是一个简单而且可行的方案,如果业务允许使用字符串类型的 ID。可以通过接口或者中间件等方式,将后端返回的长整型 ID 值转化为字符串类型,这样前端就可以安全处理这个 ID 了。通过前端框架处理。可以使用一些前端框架,如 Vue、React 等,来处理这个问题。这些框架中通常会提供 BigNumber(高精度数)这样的类库,支持对于大整数的精确处理。把 ID 值分段传输。可以将 ID 分为高低位表示,通过两个数字来传输 ID 值。这种方案需要后端和前端协同设计,不易于实现,但可以解决此问题。通过前端组件库处理。一些优秀的前端组件库中,也可能会集成处理 Big Integer 类型的组件,例如 element-ui 中就有 support-big-number 组件用于处理超大数据的问题。 总之,解决此问题的方法有很多,具体选择哪一种方案要根据业务需求和当前技术栈来确定。
如果真的需要让后端解决,在不修改实体类数据类型的基础上,我们可以使用消息转换器来实现。
消息转换器是 Spring Framework 中常用的特性之一,用于实现请求和响应的自动转换。Spring Boot 默认使用了 Jackson 模块作为消息转换器,即通过使用 Jackson 库将请求和响应中的 JSON 数据自动转换为实体类对象,或将实体类对象转换为 JSON 数据。在这个场景下,我们可以自定义一个消息转换器,使用其将后端返回的 ID 值转化为字符串类型,然后再响应给前端。
自定义消息转换器代码示例 public class JacksonObjectMapper extends ObjectMapper { public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; public static final String DEFAULT_TIME_FORMAT = "
0 Linux启动过程概述
这里先简单列一下 Linux 操作系统启动的全过程:
按下电脑的电源键后,电脑通电,BIOS启动;
BIOS读取硬盘的MBR,运行启动扇区中的代码,旧系统往往需要自己写启动扇区,而新系统基本上由专用的启动软件接管了,在 Linux 世界中,目前都是用的 Grub2。由于启动扇区空间太小,放不下太复杂的代码逻辑,所以 Grub2 也使用了多阶段启动的策略;
Grub2 负责将操作系统内核加载到内存,如果有必要,也会把 initramfs 文件加载到内存,然后将控制权交给内核;
内核进行初始化,内核的初始化过程结束后,就会把控制权交给/init程序,从此进入用户空间;
因为内核先是将 initramfs 文件挂在为根文件系统,所以刚开始运行的/init程序其实是 initramfs 文件中的,所以该文件需要的重要的初始化脚本、内核模块、配置文件等,都位于 initramfs 文件中,这也是为什么很多时候我们修改了某些配置文件后,需要先更新 initramfs 文件再重启操作系统才会生效;
initramfs 文件中的/init程序负责挂载硬盘上的文件系统,然后再把根文件系统切换到硬盘上的根分区,再运行/sbin/init程序,这时所有程序、配置文件、脚本都是使用的硬盘上的了,当然,网络文件系统也是同理。可以看出 init 程序的运行也是一个分阶段的过程;
/sbin/init程序负责系统的初始化、各种服务的运行、用户的登陆等等;
如果需要运行图形界面,则/sbin/init程序会运行 Display Manager,在 Fedora 中是 gdm,在 Ubuntu 中是 lightdm。然后 Display Manager 负责启动整个图形界面。
1 initramfs概述
initramfs 即 initram file system,翻译成中文意思就是 初始 ram 文件系统,基于 tmpfs,是一种大小灵活,直接作用在内存中的文件系统。initramfs 包含的工具和脚本,在正式的根文件系统的初始化脚本 init 启动之前,就被挂载。initramfs 是可选的,内核编译选项默认开启 initramfs(initrd)。那么什么情况下考虑使用 initramfs 呢?
加载模块,如三方驱动
定制化启动系统
制作一个很小的 rescue shell
内核不能,但是用户态可以完成的命令
initramfs 在内核启动的早期提供用一个户态环境,用于完成在内核启动阶段不易完成的工作。initramfs 包含的工具可以解密抽象层(用于加密的文件系统),逻辑卷管理器,软件 RAID,蓝牙驱动程序等。
本文是对向往大神的文章的一个笔记。
想阅读原文章移步博客园搜索向往
原文章比较长,这是一个精简和自己的一些理解
这篇文章要带着下面的问题去看
1、GPU是如何与CPU协调工作的?
2、GPU也有缓存机制吗?有几层?它们的速度差异多少?
3、GPU的渲染流程有哪些阶段?它们的功能分别是什么?
4、Early-Z技术是什么?发生在哪个阶段?这个阶段还会发生什么?会产生什么问题?如何解决?
5、SIMD和SIMT是什么?它们的好处是什么?co-issue呢?
6、GPU是并行处理的么?若是,硬件层是如何设计和实现的?
7、GPC、TPC、SM是什么?Warp又是什么?它们和Core、Thread之间的关系如何?
8、顶点着色器(VS)和像素着色器(PS)可以是同一处理单元吗?为什么?
9、像素着色器(PS)的最小处理单位是1像素吗?为什么?会带来什么影响?
10、Shader中的if、for等语句会降低渲染效率吗?为什么?
11、如下图,渲染相同面积的图形,三角形数量少(左)的还是数量多(右)的效率更快?为什么?
12、GPU Context是什么?有什么作用?
13、造成渲染瓶颈的问题很可能有哪些?该如何避免或优化它们?
1.1GPU GPU全称是Graphics Processing Unit,图形处理单元。
CPU的发展符合摩尔定律,每18个月速度翻倍。对于GPU,NVIDIA创始人黄仁勋说,GPU 的更新速度远超摩尔定律,每6个月就能翻一倍。
移动端、图形工作站类型GPU生产商,两大厂,NVIDIA和AMD。生产移动端显卡的厂商还有ARM,高通等。
DX11架构
DX11添加了hull shader,tessellator shader,domain shader。三个有点奇怪的shader
NVIDIA GPU架构发展史关键节点 :
2008–Tesla 特斯拉架构,不是真正意义上的图形处理芯片
2010–Fermi 费米架构,第一个完整的GPU计算架构,支持ECC
2012–Kepler
2014–Maxwell 添加VXGI提供实时GI,采用了MFAA抗锯齿
2016–Pascal 2017–Volta
2018–Turing 图灵架构,增加了RT core,专门用来处理光线追踪。10Giga Rays的石压地狱对光线加速计算。
单个SM结构图
每个SM内部包含64个CUDA核,8个tensor核,256kb寄存器文件。
GPU架构的共性:
GPC:图形处理簇,TPC: 纹理处理簇,Thread:线程,SM/SMX/SMM:流多处理器,Warp:线程束,SP:流处理器,Core:核心,主要是用来进行数学计算ALU:算术逻辑单元,FPU:函数处理单元,处理一些简单的数学函数运算,如平方SFU:特殊函数单元,处理一些特殊的复杂函数,如(cos,sin,log)等ROP:渲染输出单元,Load/Store Unit:加载/存储单元L1 Cache:L1缓存L2 Cache:L2缓存Memory:内存Register File:寄存器 为什么GPU内有那么多的雷同的部件?因为GPU的任务是天然并行的,所以要为高并行度设计。
2.1.GPU运行机制 2.1.1GPU运行机制 从费米架构开始,结构都比较相似。
使用一个Giga Thread Engine来管理所有正在进行的工作。
一个GPU被分成多个GPC(Graphics Processing Cluster),每个GPC拥有多个SM和一个光栅化引擎(Raster Engine)。
其中用Crossbar来进行连接GPCs和其他的功能性模块。
32个core由一个线程束(warp)来管理
程序员的shader是在SM上完成的。每个SM有许多线程执行数学运算的core。
文章目录 前言一、读取数据二、文件的纵向合并1.示例-------文件的纵向合并1.1数据说明1.2具体步骤 三、文件的横向合并2.示例---------文件的横向合并2.1数据说明2.2具体步骤 前言 主要讲了数据的读取、文件的横纵向的合并。
一、读取数据 直接读入其他格式的数据文件,例如︰Excel格式文件(扩展名为xls,xlsx等)使用“文本导向"读入文本文件(扩展名为txt, dat等)使用“数据库向导"读入数据 二、文件的纵向合并 将一个SPSS文件中的数据追加到另一个数据文件中两个SPSS数据文件应当有可以合并的内容,且最好有相同的变量名和变量类型 1.示例-------文件的纵向合并 1.1数据说明 本次使用的数据有【职工数据】和【追加职工】,数据获取已上传到资源中,自行前往下载
1.2具体步骤 (1)需求:将【追加职工】的数据合并到【职工数据】中
(2)观察数据:两张表的相同的变量名有:职工号(zgh)、性别(xb),拥有同一含义但变量名不同的变量有:职称(zc1、zc)、收入(income、sr)
(3)合并
在【职工数据】中选择【数据】----【合并文件】----【添加个案】,如下图
选择数据,可以是已经打开的数据,也可以是其他外部数据,这里选择已经准备好的【追加职工】数据,点击【继续】,如下图
将【非成对变量】里的变量放入【新的活动数据集中的变量】中,其中,将含义相同但变量名不同的变量进行【配对】,如下图
三、文件的横向合并 将一个SPSS数据文件中的若干个变量增加到另一个数据文件中两个数据文件必须有一个共同的变量名为关键字。两个数据文件应事先按关键字段升序排序 2.示例---------文件的横向合并 2.1数据说明 本次使用的数据有【职工数据】和【职工奖金】,数据获取已上传到资源中,自行前往下载
2.2具体步骤 (1)需求:将【职工奖金】的数据合并到【职工数据】中
(2)观察数据:两张表的相同的变量名有:职工号(zgh),以职工号为基准进行合并
(3)合并
在【职工数据】中选择【数据】----【合并文件】-----【添加变量】,如下图
1、在类的继承关系中,需要遵循以下哪个继承原则()
A、 多重
B、 单一
C、 双重
D、 不能继承
答案: B
2、类中的一个成员方法被下面哪个修饰符修饰,该方法只能在本类被访问() A、 public
B、 private
C、 protected
D、 default
答案: B
3、已知类的继承关系如下: A、 ass Employee;
B、 ass Manager extends Employee;
C、 ass Director extends Employee;
下语句能通过编译的是()
A、 Employee e = new Manager();
B、 Director d = new Manager();
C、 Director d = new Employee ();
D、 Manager m = new Director();
答案: A
笔记:
1.父类 xx = new 子类()定义的对象只能调用继承来的方法。
Win+R打开运行,输入“eventvwr.msc”,回车运行,打开“事件查看器”;或者右键我的电脑-管理-系统工具-事件查看器。在事件查看器中右键单击系统或安全日志,选择筛选当前日志,在筛选器中输入下列事件ID即可。
日志路径:C:\Windows\System32\winevt\Logs
查看日志:Security.evtx、System.evtx、Application.evtx
常用安全事件ID:
系统:
1074,通过这个事件ID查看计算机的开机、关机、重启的时间以及原因和注释。
6005,表示计算机日志服务已启动,如果出现了事件ID为6005,则表示这天正常启动了系统。
104,这个时间ID记录所有审计日志清除事件,当有日志被清除时,出现此事件ID。
安全:
4624,这个事件ID表示成功登陆的用户,用来筛选该系统的用户登陆成功情况。
4625,这个事件ID表示登陆失败的用户。
4720,4722,4723,4724,4725,4726,4738,4740,事件ID表示当用户帐号发生创建,删除,改变密码时的事件记录。
4727,4737,4739,4762,事件ID表示当用户组发生添加、删除时或组内添加成员时生成该事件。
安全事件ID汇总备查:
EVENT_ID 安全事件信息
1100 ----- 事件记录服务已关闭
1101 ----- 审计事件已被运输中断。
1102 ----- 审核日志已清除
1104 ----- 安全日志现已满
1105 ----- 事件日志自动备份
1108 ----- 事件日志记录服务遇到错误
4608 ----- Windows正在启动
4609 ----- Windows正在关闭
4610 ----- 本地安全机构已加载身份验证包
4611 ----- 已向本地安全机构注册了受信任的登录进程
4612 ----- 为审计消息排队分配的内部资源已经用尽,导致一些审计丢失。
4614 ----- 安全帐户管理器已加载通知包。
4615 ----- LPC端口使用无效
4616 ----- 系统时间已更改。
4618 ----- 已发生受监视的安全事件模式
4621 ----- 管理员从CrashOnAuditFail恢复了系统
4622 ----- 本地安全机构已加载安全包。
4624 ----- 帐户已成功登录
前言 现代前端对速度的追求已经进入二进制工具时代,Rust 开发成为每个人的必修课。
一般我们将常见的前端 Rust 开发分为以下几类,难度由上至下递增:
开发 wasm 。
开发 swc 插件。
开发代码处理工具。
我们将默认读者具备最简单的 Rust 知识,进行快速入门介绍。
正文 开发 wasm 意义 开发 wasm 的意义在于利用浏览器运行 wasm 的优势,在 wasm 中进行大量复杂的计算、音视频、图像处理等,当你有此类需求,可以优先考虑使用 Rust 开发 wasm 分发至浏览器。
初始化 我们使用 wasm-pack 构建 wasm ,参考 wasm-pack > Quickstart 得到一个模板起始项目。
实战 case 使用 tsify 支持输出结构体的 TypeScript 类型,实现一个简单的加法运算:
# Cargo.toml 确保你含有这些依赖 [dependencies] serde = { version = "1.0.163", features = ["derive"] } tsify = "0.4.5" use wasm_bindgen::prelude::*; use serde::{Serialize, Deserialize}; use tsify::Tsify; #[derive(Tsify, Serialize, Deserialize)] #[tsify(into_wasm_abi, from_wasm_abi)] pub struct Rect { pub width: u32, pub height: u32 } #[wasm_bindgen] pub fn plus(mut rect: Rect) -> Rect { rect.
NextJS 过去一周令人兴奋。尝试以并行方式学习和制作网站。因此,让我们深入了解到目前为止我对 Next 的了解。首先令人兴奋的是 layout.js 和路由。
任何现代网站最常见的要求是,它会有一个一致的页眉和页脚,就像第一张图片一样。rootlayout 函数只需在布局中声明即可轻松处理这些可重用组件(例如:Navbar.jsx、Footer.jsx)。它传递其他人的内容,路线作为包裹在导航栏和页脚之间的“儿童”道具。这就是内容如何变得动态,并随着路线的变化而变化。
现在我对这个网站的要求是也开发一个侧边栏。侧边栏菜单中将有许多类别来导航它们。我将在下一部分讨论动态路由/导航。但棘手的条件是侧边栏将包含在特定路径(例如产品)中,而不是其他路径(例如…/或/about)。由于我遵循基于文件夹的路由,“产品”文件夹将需要一个 layout.js 文件来处理图 2 中轻松显示的棘手情况。
products 下的 layout.js 将具有 ProductsLayout 函数,其行为与 Rootlayout 完全相同。它将在所有产品/类别路线中都有一个持久的侧边栏,但不会在其他路线中,并将获得其他动态内容作为儿童道具。是的,这很神奇。您可以使用文件夹中的布局文件处理路由或页面的任何静态部分。
如果你喜欢我的文章,记得关注获取更多的信息。感谢您的阅读,祝您有美好的一天!
遍历 public static void main(String[] args) { List<String> list = Arrays.asList("apple", "banana", "orange"); System.out.println("常规遍历"); for (String s : list) { System.out.println(s); } System.out.println("lambda遍历1"); list.forEach(System.out::println); System.out.println("lambda遍历2"); list.forEach(s -> { System.out.println(s); }); } 常规遍历 apple banana orange lambda遍历1 apple banana orange lambda遍历2 apple banana orange 排序 public static void main(String[] args) { List<String> list = Arrays.asList("apple", "banana", "orange"); System.out.println("常规排序"); Collections.sort(list, new Comparator<String>() { @Override public int compare(String o1, String o2) { return o1.
本篇文章将对几种典型的单表、多表古典密码体制进行总结,其中包括单表密码体制的Caesar体制、Playfair体制和多表密码体制的Vigenere体制、Beaufort体制以及Hill体制。并展示部分体制对应的简单例题,从而使读者更加容易理解古典密码体制是如何加减密的。
文章目录 引入一、单表古典密码体制1.Caesar体制——典型的单表加法密码体制2.标准字头密码体制——单表置换密码体制 二、多表古典密码体制1.Playfair体制2.Vigenere体制——多表加法密码3.Beaufort体制——多表加法密码4.Hill体制——广义仿射密码的特例 结束语 引入 为了方便起见,将引入英文字母表和 Z 26 Z_{26} Z26对应关系表,以此来表示字母的符号同时也将表示字母所对应的整数。
abcdefghijklm0123456789101112nopqrstuvwxyz13141516171819202122232425 一、单表古典密码体制 1.Caesar体制——典型的单表加法密码体制 加密算法: c = m + 3 m o d 26 c=m+3 \ mod\ 26 c=m+3 mod 26解密算法: m = c − 3 m o d 26 m=c-3\ mod\ 26 m=c−3 mod 26 密钥:3
Caesar密表
abcdefghijklmdefghijklmnopnopqrstuvwxyzprstuvwxyzabc 浅显一点就是 a ( a 对应的数字就是 0 ) → 0 → c = 0 + 3 = 3 → d ( 3 对应的字母就是 d ) a(a对应的数字就是0)\to 0\to c=0+3=3 \to d(3对应的字母就是d) a(a对应的数字就是0)→0→c=0+3=3→d(3对应的字母就是d)
1.在Python语言中,类的私有成员以( )开头。
private # _(一个下划线) __(两个下划线) 2.下列运算符中,整除运算符是( )
/ ** // * 3.现有d = {},Python 3解释器执行d[(1,2)] = ({3,(4)})后d的结果是( )。
报错 以上都不对 {(1, 2): ({3, 4})} {(1, 2): {3, 4}} 4.Python语句print(type(2/1))的输出结果是()。
class ‘number’ class ‘float’ class ‘int’ class ‘double’ 5.a=“我喜欢你啊,喜欢你,喜欢你。。。”
下面()可以算出a字符串中有三个“喜欢”
a.count(‘喜欢’) a.join(‘喜欢’) a.data(‘喜欢’) count( if ‘喜欢’ in a) 6.Python中,对于定义的元组tuple = (1, 2, 3, 4, 5, 6, 7 ),不能实现输出元组的全部元素的是( )。
tuple(0:7) tuple[0:len(tuple)] tuple[:] tuple 7.关于下面嵌套函数程序的输出是____________。
def outer(n): ^^^^k=8 ^^^^def inner(x): ^^^^^^^^t=x**n+k ^^^^^^^^return t ^^^^ return inner(n) print(outer(5)) 3133 31 3125 40 8.
数据页数据存储 我们知道,我们插入表的数据其实最终都要持久化到磁盘上,InnoDB为了方便管理这些数据,提出了页的概念,它会将数据划分到多个页中,每个页大小默认是16KB,这个页我们可以称为数据页。当我们插入一条数据的时候,数据都会存在数据页中,如下图所示
当数据不断地插入数据页中,数据会根据主键(没有的话会自动生成)的大小进行排序,形成一个单向链表
单个数据页的数据查找 既然数据会存在数据页中,那么该如何从数据页中去查数据呢?假设现在需要在数据页中定位到id=2的这条记录的数据,如何快速定位?有一种笨办法就是从头开始顺着链表遍历就行了,判断id是不是等于2,如果等于2就取出数据就行了。虽然这种方法可行,但是如果一个数据页存储的数据多,几十或者是几百条数据,每次都这么遍历,不是太麻烦了所以mysql想了一个好办法,那就是给这些数据分组。假设数据页中存了12条数据,那么整个分组大致如下图所示
为了方便,我这里只标出了id值,省略了其它字段的值。这里我假设每4条数据算一个组,图上就有3个组,组分好之后,mysql会取出每组中最大的id值,就是图中的4、8、12,放在一起,在数据页中找个位置存起来,这就是前面提到的数据页存储的额外信息之一,被称为页目录。假设此时要查询id=6的数据之后,此时只需要从页目录中根据二分查找,发现在4-8之间,由于4和8是他们所在分组的最大的id,那么id=6肯定在8那个分组中,之后就会到id=8的那个分组中,遍历每个数据,判断id是不是等于6即可。由于mysql规定每个组的数据条数大概为4~8条,所以肯定比遍历整个数据页的数据快的多。
上面分组的情况实际上我做了一点简化,但是不耽误理解
多个数据页中的数据查找 当我们不断的往表中插入数据的时候,数据占用空间就会不断变大,但是一个数据页的大小是一定的,当一个数据页存不下数据的时候,就会重新创建一个数据页来存储数据
mysql为了区分每个页,会为每个数据页分配一个页号,存在额外信息的存储空间中,同时额外信息还会存储当前数据页的前一个和后一个数据页的位置,从而形成数据页之间的双向链表
数据页2的页号就是2,数据页3的页号就是3,这里我为了方便理解,就直接写数据页几。并且mysql规定,前一个数据页的存储数据id的最大值要小于后一个数据页的存储数据id的最小值,这样就实现了数据在所有数据页中按照id的大小排序。
现在,如果有多个数据页,当我们需要查找id=5的数据,怎么办呢?当然还是可以用上面的笨办法,那就是从第一个数据页开始遍历,然后遍历每个数据页中的数据,最终也可以找到id=5的数据。但是你仔细想想,这个笨办法就相当于全表扫描了呀,这肯定是不行的。那么怎么优化呢?mysql优化的思路其实跟前面单数据页查找数据的优化思路差不多它会将每个数据页中最小的id拿出来,单独放到另一个数据页中,这个数据页不存储我们实际插入的数据,只存储最小的id和这个id所在数据页的页号,如图所示
为了图更加饱满,我加了一个存放数据的数据页4。此时数据页5就是抽取出来的,存放了下面三个存放数据的数据页的最小的id和对应的数据页号。如果此时查找id=5的数据就很方便了,大致分为以下几个步骤:
从数据页5直接根据二分查找,发现在4-7之间由于4和7是所在数据页最小的id,那么此时id=5的数据必在id=4的数据页上(因为id=7的数据页最小的id就是7),接下来就到id=4对应的数据页2的页号找到数据页2之后再根据前面提到的根据数据的主键id从单个数据页查找的流程查找数据 这样就实现了根据主键id到在多个数据页之间查找数据
聚簇索引 随着数据量不断增多,存储数据的数据页不断变多,数据页5的数据就会越来越多,但是每个数据页默认就16k,所以数据页5也会分裂出多个数据页的情况,如下图
数据页10的作用就跟数据页5是一样的。此时如还要查找id=5的数据,那么应该去数据页5进行二分查找呢还是去数据页10进行二分查找呢?笨办法就是遍历,但是真没必要,mysql会去抽取数据页5和数据页10存储的最小的数据的id和对应的数据页号,单独拎出来放到一个数据页中,如下图
数据页11就是新抽取的数据页,存储了id=1和对应的数据页5的页号以及数id=10和对应的数据页10的页号。而这就是B+树。一般来说,mysql数据库的B+树一般三层就可以放下几千万条数据。
此时查找id=5的数据,大致分为以下几个步骤:
从数据页11根据二分查找定位到id=5对应数据页5再到数据页5根据id=5二分查找定位到数据页3再到数据页3根据id=5查找数据,具体的逻辑前面也提到很多次了 这样就能成功查找到数据了。而这种叶子节点存储实际插入的数据的B+树就被称为聚簇索引,非叶子节点存储的就是记录的id和对应的数据页号。所以对于InnoDB存储引擎来说,数据本身就存储在一颗B+树中。
原文来自于三友的java日记
SCSI & iSCSI SCSI是Small Computer System Interface(小型计算机系统接口)的缩写,基于client-server模型,SCSI client称为initiator,server称为target。iSCSI(Internet Small Computer System Interface),Internet小型计算机系统接口,又称为IP-SAN,是一种基于因特网及SCSI-3协议下的存储技术。iSCSI是建立在TCP协议之上的块传输层协议,是一组基于块的命令,iSCSI协议使用Initiator将一组SCSI命令发送到target上执行某种操作以实现存储和数据读写。
iSCSI及基本概念 两个重要的组件启动器(initiator)和目标(target)
目标,iSCSI target是存储设备端或模拟存储设备,是存储设备,其目的是为其他主机提供网络磁盘。Linux内核LIO模块即实现iSCSI target的模拟, 详见Linux Storage Stack Diagram 。
启动器,iSCSI initiator就是能够使用target的客户端,通常是服务器。也就是说,想要连接到iscsi target的服务器,需要安装iSCSI initiator相关的软件包,如open-iscsi
Network Portal: 网络端口。在 initiator端用IP地址标识,在target端IP地址及端口IP:PORT
Session: 连接initiator和target的一组TCP连接构成。可以向 session 添加 TCP 连接,一个session中是可以有多个连接,一个 session只能看到同一个target(多网卡应用)
Connection : Initiator和target间的一个TCP连接
CID(Connection ID): 每个connection都有一个CID ,该标识在session范围内是唯一。CID由 initiator产生,在 login 请求和使用 logout 关闭 连接时传递给 target。
SSID(Session ID):一个 iSCSI Initiator 与 iSCSI Target 之间的会话(Session)由会话ID(SSID)定义,该会话ID是一个由发起方部分(ISID)和目标部分(Target Portal Group Tag)组成的元组。 ISID 在会话建立时由发起者明确指定。 Target Portal Group Tag 由发起者在连接建立时选择的 TCP端口来隐式指定
目录
确认应答(ACK)机制
超时重传机制
连接管理机制
流量控制
滑动窗口 快重传VS超时重传
拥塞控制
延迟应答
捎带应答
面向字节流
粘包问题
TCP异常情况
基于TCP应用层协议
TCP/UDP对比
用UDP实现可靠传输
listen 的第二个参数
确认应答(ACK)机制 TCP将每个字节的数据都进行了编号. 即为序列.TCP发出去的数据(报文)一般被称为数据段
我们理解TCP的发送缓冲区,我们可以将TCP的发送缓冲区,看做成一个char类型的数组。拷贝到发送缓冲区的每一个数据都有自己对应的下标。未来数据发多少,从起始位置开始偏移,以最后一个数据的下标作为序号,如要发0-100的数据,我们就以100的下标为序号,给对方传输。
每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发。
超时重传机制 主机A发送数据给B之后, 可能因为网络拥堵等原因, 数据无法到达主机B;
如果主机A在一个特定时间间隔内没有收到B发来的确认应答, 就会进行重发;
但是, 主机A未收到B发来的确认应答, 也可能是因为ACK丢失了;
因此主机B会收到很多重复数据. 那么TCP协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉.这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果.
那么, 如果超时的时间如何确定?
最理想的情况下, 找到一个最小的时间, 保证 "确认应答一定能在这个时间内返回".
但是这个时间的长短, 随着网络环境的不同, 是有差异的.
如果超时时间设的太长, 会影响整体的重传效率;
如果超时时间设的太短, 有可能会频繁发送重复的包;
超时时间不能太长也不能太短,而且超时时间不能固定,当网络好的时候,超时时间最好短一点,网络不好的时候,超时时间应该长一些。
TCP为了保证无论在任何环境下都能比较高性能的通信, 因此会动态计算这个最大超时时间
Linux中(BSD Unix和Windows也是如此), 超时以500ms为一个单位进行控制, 每次判定超时重发的超时
时间都是500ms的整数倍.
如果重发一次之后, 仍然得不到应答, 等待 2*500ms 后再进行重传.
如果仍然得不到应答, 等待 4*500ms 进行重传. 依次类推, 以指数形式递增.
BFF简介 BFF是一种Web架构,全名为Backends For Frontends,即为服务于前端的后端。这个词来源于Sam Newman的一篇文章:Pattern: Backends For Frontends。BFF一般指的是在前端与后端之间加增加一个中间层。为什么要在前端和后端之间增加一个BFF层呢?
计算机科学家David Wheeler曾经说过一句话:All problems in computer science can be solved by another level of indirection.计算机科学中的所有问题都可以通过加一层来解决。因此,需要使用BFF的场景,肯定是普通的前后端开发模式遇到了部分问题。例如在Sam Newman的文章中就描述了BFF解决多个展示端的场景。
多端展示问题 在系统一开始开发的时候只考虑了PC网页端的设计,服务器端API是为了PC网页端而服务的。但是后来随着移动互联网的兴起,移动端开始流行,决定在原有服务端的基础上开发移动端App,复用之前的API,但是原有API是为了PC端设计的,并不符合移动端的需求。
PC端的需求与移动端并不一定完全相同,现有接口无法满足所有移动端的新需求。PC端电脑性能强,可以并发请求多个接口或进行部分较复杂的数据处理,但是移动端性能低,如果使用同样的多个接口,由前端组装数据,页面展示可能会出现延迟和卡顿现象。PC端的屏幕较大,展示内容较多且全面。但是移动端屏幕小,展示内容较少。而且部分数据的获取并不容易,需要后端调用许多服务。如果移动端复用PC端接口,会获取和传输部分无用数据,不仅消耗服务端资源,还浪费网络带宽。 而且随着科技的发展和用户的需求,不同的展示端越来越多,在不仅在手机上会区分Android端,IOS端,而且还会有平板电脑端,手机网页端,PC网页端,PC的APP端等等。这些端的页面设计各不相同,对于数据的需求也不相同。假设我们复用同一个服务端和API接口,如果出现不满足需求的场景就加接口加字段,那么随着这些不同客户端的开发和迭代,服务端会变的大而臃肿,效率低下。而且同一个接口提供给太多前端调用,涉及到太多的逻辑,复杂性越来越高。
因此,更好的方式是服务端对展示进行解耦,服务端只负责提供数据,有专门的展示端负责前端的展示业务。这里的展示端就是BFF层。
不同业务场景的展示模式差异 在某些业务中,客户端的类型只有一种,但是在不同的场景下,展示的模式有差异。比如在美团的BFF实践中,不同行业的团购货架展示模块不同,是两套独立定义的产品逻辑,并且会各自迭代。
在这种业务场景下,虽然是同一个客户端,但是业务不同,需求的数据格式和类型也不同,因此遇到与上面多端展示类似的接口问题。
短生命周期的需求 还有一种情形,是闲鱼团队遇到的短生命周期的需求。在普通的业务场景下,服务端正常稳定迭代开发。但是偶尔会有一些特殊的运营活动,这种活动时间较短,可能仅仅持续几天时间。
如果仅仅为了这些几天的活动,每次都要开新API,联调,甚至修改原有服务端的逻辑,成本较大,而且较为低效。如果加一层BFF,让前端可以直接获取数据,那么开发和联调会变的简单很多。
业务整合需要 在某些情形下,业务后端和需求比较复杂,例如这篇文章涉及到的场景,有一个Moments App,包含了像用户管理,关系管理,信息,头像,点赞等多种多种后端微服务。这些服务在前端展示的逻辑耦合性较强。比如有些需要串行处理,例如得到服务1的结果才可以调用服务2;有些则可以并行处理。而数据合并和整理的逻辑额较为复杂。
图片来源:跨平台架构:如何设计 BFF 架构系统?
网易云音乐也使用BFF进行微服务的调度以及数据的组装和适配。
图片来源:基于 GraphQL 的云音乐 BFF 建设实践
这时候可以设立一个BFF层,作为一个数据整合服务,将调用不同微服务接口,与数据处理的复杂逻辑都在BFF端中实现,降低了前端的复杂度,也提高了响应效率。
处理部分展示相关的业务 在使用了BFF之后,部分页面展示相关的业务逻辑可以抽象出来,交由BFF端处理。
例如数据导出Excel下载服务,输入导入Excel上传服务。BFF层可以接收用导入的Excel,解析并处理表格数据,然后提供给服务端。在导出时,也可以调用服务端API获取数据,由BFF端整合提供给前端下载。在这种情形下,服务端只需要提供一个展示接口,就可以满足页面展示和导出两种不同格式的展示需求。导入也是同理。而且假设表格与页面展示要求的数据格式不同,例如导入时部分字段值需要作转换,那么也可以由BFF端处理这种差异。
BFF的类型 BFF本身仅仅是一个概念,实现方式有多种,在实际中我们要根据不同的场景选取不同的方案。按照大类分,主要有单一BFF和多端BFF。
单一BFF 单一的BFF主要对接服务端,根据展示服务的需求组装数据提供给每个端或者每种业务进行展示。
很多单一BFF都会用到GraphGL,他是由Facebook开发的数据查询工具。通过该工具,可以将不稳定的数据组装部分从稳定的业务数据逻辑中剥离,使数据控制逻辑前移,开发模式由“下发数据”转变成“取数据”的过程。
例如美团,闲鱼,网易云音乐等的BFF,都提供了按需查询能力,一个BFF对接多种客户端或者多种业务的需求。下图是美团使用的BFF架构设计。
图片来源:GraphQL及元数据驱动架构在后端BFF中的实践
多端BFF 多端BFF是指每种业务或者每种客户端采用自己独立的BFF层,这样每种客户端的服务更加灵活,不同的BFF端对于展示服务解耦性更高。
前端BFF与后端BFF 从技术上分,BFF又可以分为前端BFF和后端BFF。即BFF层由前端团队主导或者后端团队主导。前端团队的BFF一般使用Node.js,后端团队则会使用Java或者其他服务端语言。
如果使用前端BFF,可以实现谁使用谁开发,一定程序生避免了前后端实现的上不必要的沟通成本。但需要前端团队有一服务端开发经验,对前端团队的技术建设有较高需求。但是前端也能更深入的接触业务逻辑,对于重展示的业务需求有一定优势。例如淘宝的实践:大淘宝技术行业FaaS化实战经验分享。
传统接口与按需查询 传统接口模式即正常开发接口,固定入参和返回数据格式,供前端调用。按需查询模式即前端调用接口时指定需要哪些数据,前端自主进行按需查询。GraphQL即是使用按需查询的模式。
BFF的其他特点 与ServerLess集成 使用前端BFF时,前端开发可能缺乏运维经验,而且在高可用,并发性等问题上可能会遇到挑战。如果结合Serverless实现自动扩容,弹性伸缩等功能,可以解决一些BFF的问题。
阿里云的云原生团队介绍了这一方法:基于函数计算的 BFF 架构(图片来源)
js中获取Element元素的常用方法有以下四种:
【方法一】根据元素ID:document.getElementById()
【方法二】根据元素标签:document.getElementsByTagName()
【方法三】根据元素class名:document.getElementsByClassName()
【方法四】根据元素name名:document.getElementsByName()
需要注意的是,方法中Element后面加“s”的,返回的是数组,即便只有一个对象,也是长度为1的数组。
所以后面调用时,记得加上索引(变量名[0])
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>js获取Element元素的常用方法</title> <img id="m1" src="./img.jpg" width="200px"> <br /> <div class="cls"></div> <br /> <div class="cls"></div> <br /> <input type="checkbox" name="hobby">运动 <input type="checkbox" name="hobby">阅读 <input type="checkbox" name="hobby">游戏 </head> <body> <script> // 1 根据元素ID let img = document.getElementById("m1"); console.log(img); // 2 根据元素标签 let div = document.getElementsByTagName("div"); console.log(div); // 3 根据元素class名 let cls = document.
靶标介绍 Victor CMS v1.0 /includes/login.php 存在sql注入
步骤 1.使用burp抓包,将数据包保存为txt 2.使用sqlmap工具进行探测是否存在注入点。可以看到存在时间盲注,下面就可以用sqlmap爆出相关信息,探测注入点 sqlmap -r 1.txt 3.读取当前服务器上的文件 sqlmap -r 1.txt --file-read "/flag" --dbms Mysql -r 1.txt:这个选项告诉sqlmap从1.txt这个文件中读取HTTP请求。 --file-read "/flag":这个选项让sqlmap尝试从目标数据库服务器上读取"/flag"文件。这个行为可能会被视为一种攻击,因为它可能涉及到未经授权的文件访问。 --dbms Mysql:这个选项指定了目标数据库的类型是MySQL。 4.打开flag文件,得到flag
目录
Linux线程概念
二级页表 线程的优点 线程的缺点 线程异常 线程的用途 Linux中的线程和进程 进程和线程
进程的多个线程共享
进程和线程的关系 Linux线程控制
POSIX线程库 线程创建 线程ID及地址空间布局 线程等待 线程终止 Linux线程概念 什么是线程 在一个程序里的一个执行路线就叫做线程(thread)。更准确的定义是:线程是“一个进程内部的控制序列”。一切进程至少都有一个执行线程。线程在进程内部运行,本质是在进程地址空间内运行。在Linux系统中,在CPU眼中,看到的PCB都要比传统的进程更加轻量化。透过进程虚拟地址空间,可以看到进程的大部分资源,将进程资源合理分配给每个执行流,就形成了线程执行流。 需要明确的是,一个进程的创建实际上伴随着其进程控制块(task_struct)、进程地址空间(mm_struct)以及页表的创建,虚拟地址和物理地址就是通过页表建立映射的。 每个进程都有自己独立的进程地址空间和独立的页表,也就意味着所有进程在运行时本身就具有独立性。
但如果我们在创建“进程”时,只创建task_struct,并要求创建出来的task_struct和父task_struct共享进程地址空间和页表,那么创建的结果就是下面这样的:
此时我们创建的实际上就是四个线程:
其中每一个线程都是当前进程里面的一个执行流,也就是我们常说的“线程是进程内部的一个执行分支”。同时我们也可以看出,线程在进程内部运行,本质就是线程在进程地址空间内运行,也就是说曾经这个进程申请的所有资源,几乎都是被所有线程共享的。 如何理解进程与线程的关系?
教材观点:线程是一个执行分支,执行粒度比进程更细,调度成本更低。线程是进程内部的一个执行流。
内核观点:线程是CPU调度的基本单位,进程是承担分配系统资源的基本实体。
上面用方框框起来的内容,我们将这个整体叫做进程。因此,所谓的进程并不是通过task_struct来衡量的,除了task_struct之外,一个进程还要有进程地址空间、文件、信号等等,合起来称之为一个进程。
所以我们站在内核角度来理解进程:进程就是承担分配系统资源的基本实体。
换言之,当我们创建进程时是创建一个task_struct、创建地址空间、维护页表,然后在物理内存当中开辟空间、构建映射,打开进程默认打开的相关文件、注册信号对应的处理方案等等。而我们之前接触到的进程都只有一个task_struct,也就是该进程内部只有一个执行流,即单执行流进程,接下来我们将要接触到的,内部有多个执行流的进程叫做多执行流进程。
在Linux中,站在CPU的角度,能否识别当前调度的task_struct是进程还是线程?
答案是不能,也不需要了,因为CPU只关心一个一个的独立执行流。无论进程内部只有一个执行流还是有多个执行流,CPU都是以task_struct为单位进行调度的。因此,CPU看到的虽说还是task_struct,但已经比传统的进程要更轻量化了。
Linux下使用轻量级进程LWP模拟多线程!
为了管理好线程,有些操作系统会像进程一样单独为线程设计一套数据结构用于统筹管理线程的正常运作,比如windows就设计了线程控制块TCB隶属于PCB中,也就是说windows操作系统内核中有正线程。
而Linux内核的设计者认为,线程可以复用进程的结构体,用PCB足以模拟实现TCB的功能,所以在Linux当中没有真正的线程,而是复用了PCB的代码和结果,用轻量化进程的方案模拟实现的线程。
事实上Linux系统采取的方案更加简单,容易维护,效率更高也更安全。对于一款操作系统来说,使用最频繁的功能,除了OS本身,就是线程了。Linux正是因为采用轻量化进程LWP模拟实现多线程的方式,才能够长时间不间断的运行。
原生线程库pthread 在Linux中,站在内核角度没有真正意义上线程相关的接口,但是站在用户角度,当用户想创建一个线程时更期望使用thread_create这样类似的接口,因此系统为用户层提供了原生线程库pthread。
原生线程库实际就是对轻量级进程的系统调用进行了封装,在用户层模拟实现了一套线程相关的接口。
因此对于我们来讲,在Linux下学习线程实际上就是学习在用户层模拟实现的这一套接口,而并非操作系统的接口。
二级页表 以32位平台为例,在32位平台下一共有232个地址,也就意味着有232个地址需要被映射。
如果我们所谓的页表就只是单纯的一张表,那么这张表就需要建立232个虚拟地址和物理地址之间的映射关系,即这张表一共有232个映射表项。
每一个表项中除了要有虚拟地址和与其映射的物理地址以外,实际还需要有一些权限相关的信息,比如我们所说的用户级页表和内核级页表,实际就是通过权限进行区分的。每个应表项中存储一个物理地址和一个虚拟地址就需要8个字节,考虑到还需要包含权限相关的各种信息,这里每一个表项就按10个字节计算。
这里一共有232个表项,也就意味着存储这张页表我们需要用232 * 10个字节,也就是40GB。而在32位平台下我们的内存可能一共就只有4GB,也就是说我们根本无法存储这样的一张页表。 因此所谓的页表并不是单纯的一张表。 以32位平台为例,其页表的映射过程如下:
选择虚拟地址的前10个比特位在页目录当中进行查找,找到对应的页表。再选择虚拟地址的10个比特位在对应的页表当中进行查找,找到物理内存中对应页框的起始地址。最后将虚拟地址中剩下的12个比特位作为偏移量从对应页框的起始地址处向后进行偏移,找到物理内存中某一个对应的字节数据。 物理内存实际是被划分成一个个4KB大小的页框的,而磁盘上的程序也是被划分成一个个4KB大小的页帧的,当内存和磁盘进行数据交换时也就是以4KB大小为单位进行加载和保存的。
4KB实际上就是2的12次方个字节,也就是说一个页框中有2的12次方个字节,而访问内存的基本大小是1字节,因此一个页框中就有2的12次方个地址,于是我们就可以将剩下的12个比特位作为偏移量,从页框的起始地址处开始向后进行偏移,从而找到物理内存中某一个对应字节数据。
使用页表定位任意一个内存字节位置:页框+页内偏移,也可以说是基地址+偏移量!
这实际上就是我们所谓的二级页表,其中页目录项是一级页表,页表项是二级页表。
每一个表项还是按10字节计算,页目录和页表的表项都是2的10次方个,因此一个表的大小就是2的10次方 * 10个字节,也就是10KB。而页目录有2的10次方个表项也就意味着页表有2的10次方个,也就是说一级页表有1张,二级页表有210张,总共算下来大概就是10MB,内存消耗并不高,因此Linux中实际就是这样映射的。 上面所说的所有映射过程,都是由MMU(MemoryManagementUnit)这个硬件完成的,该硬件是集成在CPU内的。页表是一种软件映射,MMU是一种硬件映射,所以计算机进行虚拟地址到物理地址的转化采用的是软硬件结合的方式。
修改常量字符串触发段错误的原因 当我们要修改一个字符串常量时,虚拟地址必须经过页表映射找到对应的物理内存,而在查表过程中发现其权限是只读的,此时你要对其进行修改就会在MMU内部触发硬件错误,操作系统在识别到是哪一个进程导致的之后,就会给该进程发送信号对其进行终止。
线程的优点 创建一个新线程的代价要比创建一个新进程小得多与进程之间的切换相比,线程之间的切换需要操作系统做的工作要少很多线程占用的资源要比进程少很多能充分利用多处理器的可并行数量在等待慢速I/O操作结束的同时,程序可执行其他的计算任务计算密集型应用,为了能在多处理器系统上运行,将计算分解到多个线程中实现I/O密集型应用,为了提高性能,将I/O操作重叠。线程可以同时等待不同的I/O操作 【说明】
计算密集型:主要消耗CPU资源,比如文件压缩和解压、加密或者解密过程等等与算法相关的操作
IO密集型:执行流的大部分任务,主要以IO为主。比如刷磁盘、访问数据库、访问网络等。
线程不是越多越好,一定要根据CPU的个数/核心数,选择合适的线程数。
线程的缺点 性能损失:一个很少被外部事件阻塞的计算密集型线程往往无法与共它线程共享同一个处理器。如果计算密集型线程的数量比可用的处理器多,那么可能会有较大的性能损失,这里的性能损失指的是增加了额外的同步和调度开销,而可用的资源不变。健壮性降低:编写多线程需要更全面更深入的考虑,在一个多线程程序里,因时间分配上的细微偏差或者因共享了不该共享的变量而造成不良影响的可能性是很大的,换句话说线程之间是缺乏保护的。缺乏访问控制:进程是访问控制的基本粒度,在一个线程中调用某些OS函数会对整个进程造成影响。编程难度提高:编写与调试一个多线程程序比单线程程序困难得多 线程异常 单个线程如果出现除零,野指针问题导致线程崩溃,进程也会随着崩溃线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出 线程的用途 合理的使用多线程,能提高CPU密集型程序的执行效率合理的使用多线程,能提高IO密集型程序的用户体验(如生活中我们一边写代码一边下载开发工具,就是多线程运行的一种表现) Linux中的线程和进程 进程和线程 上文已提到过:进程是承担分配系统资源的基本实体,线程是调度的基本单位。
首先先下载jdk11,然后安装下载好的jdk11。
1.打开终端,创建.bash_profile
如果是第一次配置环境变量,可以使用"touch .bash_profile" 创建一个 .bash_profile 的隐藏配置文件(如果已经有存在的配置文件,则使用"open -e .bash_profile" 命令),如下图一。
2.编辑.bash_profile文件,编辑完成后关闭窗口自动保存。
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk-11.0.16.jdk/Contents/Home export JAVA_HOME CLASS_PATH=$JAVA_HOME/lib PATH=.$PATH:$JAVA_HOME/bin NDK_HOME=/Users/erwinnakashima/Library/Android/sdk/ndk/16.1.4479499 export PATH=$PATH:$NDK_HOME 3.然后输入source .bash_profile使配置生效,如下图一,输入 echo $JAVA_HOME 命令验证是否生效,如下图二(要注意的是,第一次配置之后可能不会立即生效,如果没生效,请先检查配置的是否正确,如配置正确,就先关机,然后再开机,然后就没问题了,如果还是不生效,就再配置一遍就没问题了)。
source .bash_profile echo $JAVA_HOME 如对此有疑问,请联系qq1164688204。
推荐Android开源项目
项目功能介绍:RxJava2和Retrofit2项目,添加自动管理token功能,添加RxJava2生命周期管理,使用App架构设计是MVP模式和MVVM模式,同时使用组件化,部分代码使用Kotlin,此项目持续维护中。
项目地址:https://gitee.com/urasaki/RxJava2AndRetrofit2
一、mysql的集群部署方案 MySQL 集群部署方案有以下几种:
MySQL Cluster:MySQL 官方提供的 MySQL 集群方案,它通过对 MySQL 的源码进行修改,实现了 MySQL 集群的分布式功能。
Galera Cluster:Galera Cluster 是一个基于 MySQL 的高可用性解决方案,它通过对 MySQL 的主从复制功能进行扩展,实现了 MySQL 集群的高可用性和扩展性。
Percona XtraDB Cluster:Percona XtraDB Cluster 是一个基于 MySQL 的高可用性解决方案,它通过对 MySQL 的主从复制功能进行扩展,实现了 MySQL 集群的高可用性和扩展性。
MySQL Replication:MySQL Replication 是 MySQL 官方提供的高可用性方案,它通过对 MySQL 的主从复制功能进行扩展,实现了 MySQL 集群的高可用性。
MySQL Proxy:MySQL Proxy 是一个 MySQL 代理,它可以将多个 MySQL 实例转化为一个 MySQL 集群,提供了对 MySQL 集群的负载均衡、故障转移等功能。
二、docker部署mysql主从复制(一主多从) 主节点
准备docker-compose.yml文件
version: '3.1' services: mysql-master: image: mysql:8.0.32 container_name: mysql-master restart: always network_mode: "
我相信点进这个博客的都是一些cesium专业人才,这文章只起了一个抛砖引玉的作用,希望各位人才不惜赐教。
Github地址:CesiumGS/cesium-native (github.com)
编译需求:升级公司的3dtile的架构,提高性能
博客目的:寻找一些志同道合的朋友,本人研二实习生,希望可以得到各位指点
编译难度是有的,尤其对一些c++不熟悉的人,还有对网络不好的人也不太友好。
目录
1.下载代码(Win)
1.1使用官网的命令行(适合网速好的,魔法极其稳定的)
1.2手动下载代码以及依赖(适合网速不好的,最好有魔法的)
2.编译(Win)
3.cesium-native-tests.exe分析
1.下载代码(Win) 1.1使用官网的命令行(适合网速好的,魔法极其稳定的) 根目录下进行这个操作,拉取代码和依赖
git clone git@github.com:CesiumGS/cesium-native.git --recurse-submodules 如果上述命令在拉取某个依赖失败了,网络超时,执行下面的,可以重复执行,但是不推荐,有些依赖必须手动下载,可能是我魔法不够强大
git submodule update --init --recursive 1.2手动下载代码以及依赖(适合网速不好的,最好有魔法的) 直接下载压缩包,然后解压,如下。
看到了.gitmodules了嘛,这个是控制下载依赖的
url就地址,到对应的网址下载zip,然后放到extern中就行,记得文件夹名字改的与如上一致
经过漫长的下载,你们应该都下载好了,接下来开始编译
2.编译(Win) 选择编译一种就行,在根目录下进行
cmake --build build --config Release 这边一般都是可以编译通过的,你的visual studio是64位,cmake功能都是正常的
进入软件,需要编译这个,编译这个整个程序都有了
编译过了后,进入到如下目录
这个exe就是编译出来的。
3.cesium-native-tests.exe分析 参数极其复杂,目前我还是没搞懂。
-l 是看有什么测试功能的。
比如看一下Reads tileset JSON
可以看到目录多了一个a.txt
打开
我也不是很懂,这是啥情况。-f是一个输入文件,-o是一个保存当前操作的日志一样,请大佬教我。
1、注册gitee账户并登录
2、点击➕新建仓库
3、填写仓库名称、路径、仓库介绍和选择是否开源,其他的一律默认,然后点击创建(其他的是初始化仓库的,本地有仓库的,不需要初始化)
4、推送仓库之前,配置SSH公钥(限制推送人。还有一种方法是输入登录Gitee时的用户名和密码)
4.1、输入指令生成SSH公钥
ssh-keygen -t rsa
4.2、不断回车(不需要输入其他内容)【如果公钥已存在会自动覆盖】
5、Gitee设置账户共同公钥
5.1、获取公钥
cat ~/.ssh/id_rsa.pub
5.2、复制公钥,打开Gitee,点击用户下的设置,找到SSH公钥,粘贴复制的公钥,点击确定
5.3、验证配置是否成功(第一次访问出现提示,输入yes)
ssh -T git@gitee.com
6、把本地仓库推到远程仓库
6.1、复制仓库地址
6.2、输入如下添加远程仓库(告诉本地仓库,远程仓库是哪个。一般一个本地仓库对应一个远程仓库。一般默认远端名字是origin,仓库路径从远端服务器获取。)
git remote add 远端名字 远程仓库地址
6.3、检查添加是否成功
git remote
6.4、同步本地代码到远程仓库(把对应分支推给远程仓库)【类似于快进模式的合并merge】
git push 远端名字 本地分支名字:远端分支名(远程分支名字和本地分支名字一样的可只写一个)
6.5、去Gitee仓库中查看
拓展: 1、(6.4)完整代码:git push -f --set-upstream 远端名称 本地分支名:远端分支名
-f:强制覆盖 --set-upstream:推送到远端同时建立起和远端分支的关联关系(第一次推送可以使用这个命令,以后的推送就可以直接简写)
例如:git push --set-upstream origin master(把本地master推送到远端master,同时绑定关系,方便下次推送)
git branch -vv:查看本地分支和远程分支的关系
如果当前分支已经和远端分支关联(使用了--set-upstream),则可以省略分支名和远端名
git push (将master分支推送到已关联的远端分支)
2、将远程仓库克隆到本地(一般只克隆一次)
2.1、获取远程仓库克隆地址
2.2、输入命令克隆
git clone 远程仓库路径 本地目录(本地目录省略的话会自动生成一个目录)
3、从远程仓库中拉取和抓取(远程分支和本地分支一样,可以进行merge操作,只需要把远端仓库更新到本地,再进行操作)
3.1、抓取(remote name:远端名称 branch name:远端需要拉去的分支名)
【抓取指令只将远端仓库更新都抓取到本地,但是不会合并,需要用merge合并。不指定远端名和分支名,则抓取所有分支】
Eigen库
网址: Eigen
用处:其他库依赖的基础库;建议这个库没事儿多看看。
OpenMesh库
网址:OpenMesh - Computer Graphics and Multimedia
用处:网格数据读取,数据结构,遍历查询;其也被CGAL依赖,作为网格结构化存储的一部分。
CGAL库
网址: The Computational Geometry Algorithms Library
用处:点云,三角网处理的算法;特别重要也特别难理解;语法难度与算法难度并难,中文资料极其的少,建议硬着头皮看英文文档(虽然名词很多很难懂,但是也得啃)。
GTE数学库
网址:Geometric Tools
用处:只是用了其中的B样条曲线拟合部分和平面构三角网(效果不理想),这个库处理效率比较低,只是能实现功能。
libigl库
网址: libigl
用处:轻量级的CGAL,效率和稳定性很一般。用了其中的ICP配准,进行了大量魔改;
LibIGES
网址:GitHub - cbernardo/libIGES: Implementation of the IGESv5.3 specification
用处:主要是把生成的B样条存储为igs格式。此库功能就是这么单一,开源的仅有的两个支持igs读写的库,另外一个OCCT变态的庞大,拆分又相当困难。
boost
网址:https://github.com/boostorg/boost
用处:C++算法模板库。
设总体 X X X~ N ( μ 1 , σ 1 2 ) N(\mu_1,\sigma_1^2) N(μ1,σ12), Y Y Y~ N ( μ 2 , σ 2 2 ) N(\mu_2, \sigma_2^2) N(μ2,σ22)相互独立,为检验右侧假设 H 0 : σ 1 2 / σ 2 2 ≤ 1 , H 1 : σ 1 2 / σ 2 2 > 1 H_0:\sigma_1^2/\sigma_2^2\leq1,H_1:\sigma_1^2/\sigma_2^2>1 H0:σ12/σ22≤1,H1:σ12/σ22>1(或左侧假设 H 0 : σ 1 2 / σ 2 2 ≥ 1 , H 1 : σ 1 2 / σ 2 2 < 1 H_0:\sigma_1^2/\sigma_2^2\geq1,H_1:\sigma_1^2/\sigma_2^2<1 H0:σ12/σ22≥1,H1:σ12/σ22<1),检验统计量为 S 1 2 S 2 2 \frac{S_1^2}{S_2^2} S22S12~ F ( n 1 − 1 , n 2 − 1 ) F(n_1-1,n_2-1) F(n1−1,n2−1)。其中, S 1 2 S_1^2 S12和 S 2 2 S_2^2 S22分别为样来自 X X X和 Y Y Y的样本方差, n 1 n_1 n1, n 2 n_2 n2为样本容量。下列代码定义了计算单侧假设 H 0 H_0 H0的p值检验函数。
14.1 引言 本章讨论高级I/O相关主题,包括:
非阻塞I/O;记录锁;I/O多路转接(select、poll);异步I/O;readv和writev函数;存储映射I/O(mmap)。 14.2 非阻塞I/O 非阻塞I/O使我们可以发出open、read和write这样的I/O操作,并使这些操作不会永久阻塞。如果这种操作不能完成,则调用立即出错返回,表示该操作如继续执行将阻塞。
对于一个给定的描述符,有两种为其指定非阻塞I/O的方法:
(1)如果调用open获得描述符,则可指定O_NONBLOCK标志;
(2)对于已经打开的一个描述符,则可调用fcntl,由该函数打开O_NONBLOCK文件状态标志。
14.3 记录锁 记录锁的功能是:当第一个进程正在读或修改文件的某个部分时,使用记录锁可以阻止其他进程修改同一文件区。
1. 历史
2. fcntl记录锁
#include <fcntl.h> int fcntl(int fd, int cmd, .../* struct flock *flockptr */); // 返回值:若成功,依赖于cmd(见下),否则,返回-1 cmd 是 F_GETLK、F_SETLK 或 F_SETLFW;
第三个参数 flockptr 是一个指向flock结构的指针:
struct flock { short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */ short l_whence; /* SEEK_SET, SEEK_CUR, or SEEK_END */ off_t l_start; /* offset in bytes, relative to l_whence */ off_t l_len; /* length, in bytes; 0 means lock to EOF */ pid_t l_pid; /* returned with F_GETLK */ }; 所希望的锁类型:l_type可取 F_RDLCK(共享读锁)、F_WRLCK(独占性写锁)或 F_UNLCK(解锁一个区域);要加锁或解锁区域的起始字节偏移量:l_start 和 l_whence;区域的字节长度:l_len;进程的ID(l_pid)持有的锁能阻塞当前进程(仅由F_GETLK返回)。 共享读锁(F_RDLCK)和独占性写锁(F_WRLCK)的基本规则:任意多个进程在一个给定的字节上可以有一把共享的读锁,但是在一个给定的字节上只能有一个进程有一把独占写锁;如果在一个给定字节上已经有一把或多把读锁,则不能在该字节上再加写锁;如果在一个字节上已经有一把独占性写锁,则不能再对它加任何读锁。
简介 众所周知,Android平台的管理机制下,App进入后台后,为了提供持续的及时服务(如推送、音乐),或进行驻留获取收益(跟踪、信息收集、广告)等,会利用一些方法来让自身保持活跃,躲过被Android系统或用户发觉、清理,实现后台驻留。
其中,后台驻留的广义概念,除了保持在后台运行外,被其他组件拉起也属于驻留(唤醒)。
由于驻留会对系统的性能、响应延迟、续航、发热等带来负面影响,令系统的资源管理效果降低,属于违背用户意愿和知情的恶劣行为,因此将这些App称为顽固(Diehard)应用,其利用的方法称为顽固方法。
除了App利用的一些黑科技(甚至是在违法边缘的擦边手段)以外,Android系统本身自带的机制也可以实现保活和拉起。这些保活、拉起机制,粗略划分为两类:
保持活跃,在后台运行不被清理、回收被其他组件唤醒,包括被其他App唤醒、被系统提供的功能唤醒 本文总结上述这两类会被顽固App利用的机制。
进程和Task管理 首先简单梳理一下Android Framework层基本的进程管理。
Android平台基于Linux,除了基于Linux的“进程”维度来进行管理外,还按照Task的概念来管理应用进程,分别为ProcessRecord和TaskRecord。系统可以按Task也可以按Process来管理进程。
Android提供接口直接杀死Linux进程:1. ProcessRecord的kill()方法,其实现是向对应的进程发送SIGNAL_KILL信号;2. libc的kill()函数,也是发送信号
OOM终止进程(LMK) App进程在系统中根据OOM(Out of Memory)ADJ(Adjustment)级别和进程状态来确定优先级,当系统需要杀死进程来释放内存时,优先级越低的会优先终止。OOM ADJ分数越小优先级越高。
由于顽固App进程后台驻留时可能会被系统回收,因此顽固App通常通过一些手段(services、弹窗)等来降低OOM(提高优先级),减少自身被系统回收的几率。
最近任务列表结束Task 用户在多任务界面(Recents)移除应用,系统会结束应用对应的Task:Removing Recent Task Item(RRT)。
该操作会结束掉与Task关联的进程,但在一些场景下仍然会有对应App的进程没有被杀死。
当App通过"Exclude from recents"功能(不在最近任务列表显示自己)时,没有提供给用户结束的机会,就没有手动结束掉Task的入口当一个进程属于多个Task时(该进程还需要为其他Task服务) 这类终止机制由用户操作触发,当顽固应用借助多进程、多任务、唤醒拉起、互拉等操作,被终止后仍在后台运行(或后续又被唤醒),给用户感受为“杀不干净”。
强制结束App 强制结束(Force-Stop)时Android内建的功能,由ActivityManagerService提供接口,可以在设置-应用程序界面由用户手动调用。
强制结束的范畴是App对应的所有Task(即可以杀死一般App所有进程)。FSA还额外会将App设置为“STOPPED“状态,禁止应用在下一次被用户手动启用或应用跳转前被广播、服务等唤醒。强制结束对顽固App的效果不佳,许多顽固App具备Native保活能力、互拉保活、唤醒拉起等对抗措施。
此外,Android提供KILL_BACKGROUND_PROCESSES权限,允许具备权限的App调用API杀死ADJ大于SERVICE_ADJ的后台进程(即没有Service的后台进程可以被杀掉)。
保持活跃或唤醒 从最近任务隐藏或多个最近任务 Android平台提供的excludeFromRecents功能可以让App的Task在多任务中隐藏。此外一个进程可以属于不同的Task,产生多个Task并隐藏其中几个Task可以实现”杀不干净“的效果。
提升App进程优先级、阻止部分回收场景 LMK和OOM ADJ会受到进程状态和优先级的影响,提高优先级可以降低被系统回收的几率,阻止部分会杀进程的场景。
其中,将借助前台进程绑定后台服务进程保活的手段,是较常见的“杀不死、杀不干净”的情况(最近任务移除后仍有进程)。
接收广播,启动Receiver,具有Receiver的后台进程优先级高于无Receiver的后台进程创建前台Service(高版本Android前台service需要带有通知),OOM ADJ更低(SERVICE_ADJ),杀死概率更低,此时进程不会被“杀死后台进程”杀掉(会跳过ADJ小于等于SERVICE_ADJ的进程)保持前台Activity,OOM ADJ更低(用户可见的Task)创建前台窗口(悬浮窗)或覆盖窗口(将窗口盖在前台App上面)将后台服务绑定到前台进程,赋予后台服务在的进程更低的OOM,提升该进程的优先级,减少被杀的几率;同时对应进程不再属于后台进程,不会被“杀死后台进程”杀死,且该进程转为“需要为其他Task服务”,同样不会被最近任务移除时杀死对于涉及Service的场景,ContentProvider也适用 借助Sticky Service唤醒 黏性Service是系统提供的机制,被杀死后会由系统调度进行重启。前述的force-stop杀死的进程,由于设置的“STOPPED”状态是会被跳过的,因此这种情况杀死的进程不会再自动重启。大多数ROM对此都有限制(次数、频率)。
借助广播唤醒 通过系统或其他App、组件发出的广播可以唤醒应用,顽固应用可以借助广播来完成唤醒自启。同样的,force-stop设置的“STOPPED”状态也会让广播跳过这些App,不会唤醒这些App来传递广播。但广播带有一个特例功能,带有FLAG_INCLUDE_STOPPED_PACKAGES的广播可以无视“STOPPED状态”,仍会唤醒force-stop的App。通常系统广播没有这个FLAG,基本上是其他应用发出的广播带有。
高版本的Android已经不再触发静态广播和隐式广播,这种唤醒方式少了很多。(但有FLAG_RECEIVER_INCLUDE_BACKGROUND和FLAG_INCLUDE_STOPPED_PACKAGES规避)
借助Alarm Service定时器唤醒 Alarm是Android提供的定时器功能,定时器timeout时会唤醒App。被force-stop的应用会自动移除掉注册的定时器,因此不会被唤醒。
借助Job Scheduling Service任务调度唤醒 与Alarm类似,定时唤醒App。但是受到电源管理策略、功耗管理策略、系统休眠状态、WorkManager等的影响,唤醒的定时精度较低,且不同ROM可能表现一致性较差。同样的,会跳过被force-stop的App。
借助其他App拉起唤醒 这是国内互联网App最恶心的一种机制,一群App(或集成的SDK)互相拉起对方、互相绑定提高优先级、互相拉起唤醒。其中,唤醒方式除了常规的四大组件外,还有一些黑科技、Native的方法。其中,App发出的广播带上FLAG_RECEIVER_INCLUDE_BACKGROUND和FLAG_INCLUDE_STOPPED_PACKAGES完全可以规避force-stop后"STOPPED"的应用,实现唤醒。
总结 可以说,Android本身的管理机、提供的组件间通信功能,叠加App们的流氓行为,可以说后台驻留、拉起唤醒是防不胜防的,实现较好的后台驻留管理需要较高的投入,且对系统稳定性、App基本功能的影响较大,是高投入高难度的研究方向。其中,App互拉唤醒和保活的机制,让force-stop机制做不到太好的效果,其"STOPPED"实现的类似的轻度冻结状态几乎报废,也是各大ROM厂商在后台管理部分大展身手的重要因素。
为了实现好的功耗、续航、性能,就需要在应用唤醒、冻结、暂停执行等方面下功夫了。
以下逻辑题,用Java编程语言,并尽量考虑时间和空间优化
1、实现以下2个接口不能使用语言的基本分割组合函数(如Java的String.split,php的explode和implode)
(1)字符串拆分成数组,如“ab&&2”通过”&&“做分隔符,分割得到字符串数组[“b”,“2”]
public static List<String> splitString(String s, String delim) { List<String> res = new ArrayList<>(); int start = 0; for (int i = 0; i < s.length(); i++) { if (i + delim.length() <= s.length() && s.substring(i, i + delim.length()).equals(delim)) { res.add(s.substring(start, i)); start = i + delim.length(); } } res.add(s.substring(start)); return res; } 示例
System.out.println(splitString("ab&&2", "&&")); // ["ab", "2"] System.out.println(splitString("hello world", " ")); // ["hello", "world"] System.out.println(splitString("hello||world||java", "
Vue-Rate评分组件的相关使用: 基本用法([ ] 内容为测试内容,可以按照自己代码修改):
<el-rate v-modeal:[value(绑定数值)] disabled:[(组件是否可读,默认为:false)] :colors="colors"[(评分的组件颜色设置)] @change="Change"[(评分改变时触发该事件)] > </el-rate> <script> export default { name:"Test", data(){ return{ value:null, colors: ['#99A9BF', '#F7BA2A', '#FF9900'] } }, methods:{ Change(value) { console.log(value); } } </script> 更多详细: https://element.eleme.cn/#/zh-CN/component/rate (element官网关于Rate评分组件) 进阶用法(与Form表单相结合):
<el-table-column prop="[number(表单项数值)]" label="评分"> <template slot-scope="scope"> <el-rate disabled v-model="[scope.row.number(绑定该表单项的数值)]" :colors="colors"> </el-rate> </template> </el-table-column> <script> export default { name:"Test", data(){ return{ colors: ['#99A9BF', '#F7BA2A', '#FF9900'] } } </script>
第6期 两地三中心解决方案SDRS+CBR 1.方案概述什么是两地三中心什么是SDRS什么是CBR什么是两地三中心容灾方案(SDRS+CBR)应用场景方案优势三种容灾方案对比 2.两地三中心方案原理生产站点正常工作生产站点故障生产站点和跨可用区容灾站点同时故障 3.资源和成本规划部署跨可用区容灾部署跨区域容灾 1.方案概述 什么是两地三中心 两地三中心是一种业务连续性容灾方案。三数据中心并存的特性,能在任意两个数据中心受损的情况下保障核心业务的连续,大大提高容灾方案的可用性。
将华为云的SDRS与CBR结合使用,可以较快地响应小范围的故障和较大范围的自然灾害,保全业务数据,保障业务的连续性
两地三中心容灾方案包括了生产中心、同城灾备中心和异地灾备中心:
生产中心:对外提供服务同城灾备中心:通常在离生产中心几十公里的距离建立同城灾备中心,应用可在不丢失数据的情况下切换到同城灾备中心运行,是两地三中心容灾方案的第一级容灾保护异地灾备中心:通常在离生产中心几百或者上千公里的地方建立异地灾备中心,应对区域性重大灾难,实现周期性异步复制灾备,是两地三中心容灾方案的第二级容灾保护 什么是SDRS 存储容灾服务(Storage Disaster Recovery Service,SDRS)是一种为弹性云服务器、云硬盘和专属分布式存储等服务提供容灾的服务。通过存储复制、数据冗余和缓存加速等多项技术,保障用户数据的可靠性以及业务的连续性。
什么是CBR 云备份(Cloud Backup and Recovery,CBR)是一种为云内的弹性云服务器、云耀云服务器、裸金属服务器、云硬盘、SFS Turbo文件系统、云下VMware虚拟化环境和云下主机上的单个或多个文件以及数据库,提供简单易用备份的服务。针对病毒入侵、人为误删除、软硬件故障等场景,可将数据恢复到任意备份点,保障用户数据的安全性和正确性,确保业务安全。
什么是两地三中心容灾方案(SDRS+CBR) 两地三中心容灾方案(SDRS+CBR)通过SDRS将生产站点的数据同步复制到同区域下的不同可用区,形成跨可用区容灾站点;通过CBR将生产站点的数据周期性备份到不同区域,形成跨区域容灾站点。生产站点、跨可用区容灾站点、跨区域容灾站点共同组成两地三中心架构,满足两地三中心容灾方案的诉求。
这里的跨可用区容灾站点,对应上述两地三中心中的同城灾备中心,跨区域容灾站点对应两地三中心中的异地灾备中心。
下文中两地三中心容灾方案(SDRS+CBR)简称为SDRS+CBR容灾方案。
两地三中心容灾方案(SDRS+CBR)中,“两地”是指容灾方案部署在两个区域,“三中心”分别是一个生产站点、一个同区域跨可用区容灾站点(下文简称为跨可用区容灾站点)和一个跨区域容灾站点。
两地三中心容灾方案(SDRS+CBR)分别通过SDRS将生产站点的数据同步地复制到跨可用区容灾站点,通过CBR将生产站点的数据周期性地备份到跨区域容灾站点,满足两地三中心的诉求。
应用场景 SDRS+CBR容灾方案适用于使用弹性云服务器和云硬盘运行业务的场景。
方案优势 相比跨可用区容灾和跨区域容灾的“双站点”容灾方案,SDRS+CBR容灾方案结合两者的优势,可以同时应对可用区级别故障和区域级别灾难。
对于可用区级别故障,容灾切换时保证磁盘数据一致性。对于区域级别灾难,该方案可将业务恢复至最近一次备份时间点,尽可能保全业务数据不丢失。 三种容灾方案对比 容灾方案是否可以应对可用区级别故障可用区级别故障切换后,是否可以恢复至崩溃时的状态是否可以应对区域级别灾难跨可用区容灾(SDRS)√√×跨区域容灾(CBR)√×√两地三中心容灾方案(SDRS+CBR)√√√ 2.两地三中心方案原理 本章节分别通过生产站点正常工作、生产站点故障以及生产站点和跨可用区容灾站点同时故障三个场景,介绍在不同的故障情况下,本方案如何接管用户的业务
生产站点正常工作 当生产站点正常工作时,状态如图1所示。
通过SDRS,在区域A内将可用区1的生产站点服务器的数据、配置信息同步复制到可用区2的跨可用区容灾站点,为跨可用区容灾做准备。日常可定期进行容灾演练,模拟真实故障恢复场景,制定应急恢复预案。通过CBR,对位于区域A的生产站点服务器进行周期性整机备份,然后周期性将整机备份复制到区域B的跨区域容灾站点,为跨区域容灾做准备。
图1 生产站点正常工作
生产站点故障 在出现设备故障等小范围的故障,造成生产站点不可用时,应用可在不丢失数据的情况下切换到跨可用区容灾站点运行,如图2所示。
该阶段的容灾RPO(Recovery Point Objective)等于0,RTO(Recovery Time Objective)在30分钟内。
说明:
RPO:最多可能丢失的数据的时长。
RTO:从灾难发生到整个系统恢复正常所需要的最大时长。
图2 生产站点故障
生产站点和跨可用区容灾站点同时故障 在出现自然灾害地震等大范围灾难,造成生产站点和跨可用区容灾站点同时不可用时,应用可以切换到跨区域容灾站点。通过周期性复制到区域B的整机备份创建整机镜像,然后使用整机镜像创建云服务器,在跨区域容灾站点恢复应用,保证业务连续运行,如图3所示。
该阶段的容灾RPO取值为0 ~ 周期性备份间隔,当前备份间隔最小为1小时,RTO在30分钟内。
说明:
跨区域容灾阶段,RPO = 发生灾难时间点 - 最新的备份文件时间点。
图3 生产站点和跨可用区容灾站点同时故障
3.资源和成本规划 本章节介绍最佳实践中资源规划情况,实际业务中还需要考虑资源规格的不同每月费用的变化或是每年费用才能实现资源和成本的最佳规划。
PostgreSql根据给的时间范围统计15分钟粒度、小时粒度、天粒度、周粒度、月粒度工单 说明实现15分钟粒度工单统计小时粒度工单统计天粒度工单统计周粒度工单统计月粒度工单统计 说明 项目有个需求是统计故障工单每15分钟、每小时、每天、每周和每月共有多少工单。
这里先做个笔记,怕以后忘记怎么使用。
如果不知道generate_series()函数用法,可以参考我的这篇博客进行了解:数据库(postgresql和mysql)统计一个范围内的日期,没有当天日期的数据统计补0
实现 这里只统计2022-10-27那一天的数据,可以看到这天一共有160条数据。
然后我们根据时间分组看看,每个时间段都有多少数据,可以看到我们表中的时间格式是yyyy-MM-dd HH24:mi:ss这种年月日时分秒的格式。数据库表里面create_time类型为timestamp。
15分钟粒度工单统计 在实际开发中,我们就只需要传一个开始时间和结束时间这2个参数就行。
代码中只有2个参数,一个#{startTime}代表开始时间,一个#{endTime}代表结束时间,代码里面传给mybatis的时间类型为String字符串,格式为yyyy-MM-dd或者yyyy-MM-dd HH24:mi:ss都行,因为这里有用cast将时间格式转为timestamp(yyyy-MM-dd HH24:mi:ss)这种类型。
原mybatis中sql代码:
select '故障' type,c.date, coalesce(d.order_num,0) order_num, coalesce(d.archived_num,0) archived_num, coalesce(d.timeout_soon_num,0) timeout_soon_num, coalesce(d.no_timeout_num,0) no_timeout_num, coalesce(d.order_inprogress,0) order_inprogress, coalesce(d.order_overtime,0) order_overtime from (select to_char(t,'yyyy-MM-dd HH24:mi:00') date from generate_series(cast(#{startTime} as timestamp),cast(#{endTime} as timestamp),'15 minute') t) c left join (select to_char(b.starttime,'yyyy-MM-dd HH24:mi:00') date, count(distinct a.ticket_id) order_num, count(distinct case when a.ticket_status ='已归档' then a.ticket_id end) archived_num, count(distinct case when a.ticket_status !='已归档' and a.
计算机网络自顶向下方法 链路层和局域网 6.1 链路层概述6.1.2 链路层在何处实现 6.2 差错检测和纠正技术6.2.2 检验和(TCP和UDP用的)6.2.3 循环冗余检测 6.3 多路访问链路和协议6.3.1信道划分协议6.3.2随机接入协议6.3.3 轮流协议 6.4 交换局域网6.4.1 链路层寻址和ARP6.4.2 以太网 6.1 链路层概述 尽管任一链路层的基本服务都是将数据报通过单一链路从一个节点移动到相邻节点,但所提供的细节随着链路层协议的不同而变化。链路层协议所能提供的可能包括
成帧:在每个网络层数据报经链路传送之前,几乎所有的链路层协议都是将其用链路层帧封装起来。链路接入:媒体访问控制协议规定了帧在链路上的规则。可靠交付:当链路层协议提供可靠的服务时,它保证无差错地经链路层移动到每个网络层数据报差错检测和纠正:当帧中的一个比特作为 1 传输时,接收方节点中的链路层硬件可能不正确地将其判断为 0,反之亦然。这种比特差错是由信号衰减和电磁噪声导致的。因为没有必要转发一个有差错的数据报,所以许多链路层协议提供一种机制来检测这样的比特差错。通过让发送节点在帧中包括差错检测比特,让接收节点进行差错检查,以此来完成这项工作。 6.1.2 链路层在何处实现 链路层的主体部分是在网络适配器中实现的,网络适配器有时也称为网络接口卡位于网络适配器核心的时链路层控制器,该控制器通常是一个实现了许多链路层服务(成帧、链路接入、差错检测)的专用芯片,但部分链路层是在运行于主机 CPU 上的软件中实现的。链路层的软件组件实现了高层链路层功能,如组装链路层寻址信息和激活控制器硬件。在接收端,链路层软件响应控制器中断(例如,由于一个或多个帧的到达),处理差错条件和将数据报向上传递给网络层。所以,链路层是硬件和软件的结合体。
在发送端,控制器取得了由协议栈较高层生成并存储在主机内存中的数据报,在链路层帧中封装该数据报(填写该帧的各个字段),然后遵循链路接入协议将该帧传进通信链路中。在接收端,控制器接收了整个帧,抽取出网络层数据报。如果链路层执行差错检测,则需要发送控制器在该帧的首部设置差错检测比特,由接收控制器执行差错检测。
6.2 差错检测和纠正技术 假设要发送的信息 D 有 d 比特。在偶校验方案中,发送方只需包含一个附加的比特,选择它的值,使得这 d+1 比特(初始信息加上一个校验比特)中 1 的总数是偶数。对于奇校验方案,选择校验比特值使得有奇数个 1。下图描述了一个偶校验的方案,单个校验比特被存放在一个单独的字段中。
但是如果出现了偶数个比特差错,就无法检测出来。
单比特奇偶校验方案的二维一般化方案。这里 D 中的 d 个比特被划分为 i 行 j 列。对每行和每列计算奇偶值。产生的 i+j+1 奇偶比特构成了链路层帧的差错检测比特。
假设在初始 d 比特信息中出现了单个比特差错。使用这种二维奇偶校验 (two-dimensional parity)方案,包含比特值改变的列和行的校验值都将会岀现差错。 因此接收方还可以利用存在奇偶校验差错的列和行的索引来实际识别发生差错的比特并纠正它。二维奇偶校验也能够检测(但不能纠正!)一个分组中两个比特差错的任何组合。
6.2.2 检验和(TCP和UDP用的) 一个简单检验和方法就是将所有比特的整数加起来,并且用得到的和作为差错检测比特。因特网检验和(Internet checksum)就基于这种方法,即数据的字节作为 16 比特的整数对待并求和。这个和的反码形成了携带在报文段首部的因特网检验和。接收方通过对接收的数据(包括检验和)的和取反码,并且检测其结果是否为全 1 比特来检测检验和。如果这些比特中有任何比特是 0,就可以指示出差错。
6.2.3 循环冗余检测 CRC运算实际上就是在数据长为k的后面添加供差错检测用的n位冗余码,然后构成帧k+n位发送出去。
【凡亿】Cadence Allegro 17.4零基础入门66讲PCB Layout设计实战视频_哔哩哔哩_bilibili
写在这里,以后可以翻一翻。
原理图部分
一,capture 软件操作界面及常用设置(软件选择orcad capture cis)
1.颜色,格点设置(options-->perferences)
左边是原理图格点,右边是元器件的格点设置
2.背景设置
原理图背景默认是黑色;若要改成白色,将Dark 改成light.
注意,设置后需要重新启动软件才会有效。
二,库文件
位置 D:\Cadence\SPB_17.4\tools\capture\library
文件是.OLB格式,一共46个。
IC封装网 (凡亿),可以下载原理图库和PCB库。 系统自带的库:常用红色标记的3个库。电源,连接器,分立元器件。
晶体管库
三,创建元器件库
当一个元件有2个部分时,创建界面有A,B提示,分别进行编辑;
添加元件时候,也有A,B选择。
四,元器件库的管理和调用
五,元器件库与封装关联
六,原理图新建,添加命令
七,原理图添加元器件
八,原理图信号联通
九,电源和地联通
十,原理图添加BUS总线
十一,原理图添加差分属性
十 二,原理图PCB footprint处理
十 三,原理图DRC检查
按照默认的设置即可,不需要修改。
①17.4版本DRC检查移到了PCB选项下面。
② DRC检查时注意,文件夹名称不能有中文,否则会报错。
电器检查和物理检查英文解释如下
十 四,原理图PDF和BOM清单输出
原理图PDF输出有2种方法:
1.file-》export->PDF
(需要安装Ghostscript,且还需要安装Adobe 专业板软件,一般的版本打不开)
2.file-》print (推荐这个方法)
这里需要设置一下打印机,选择安装的PDF软件,一般会有一个对应的虚拟打印机,选择一个即可,比如福昕阅读器
BOM清单输出
添加一项PCB封装栏输出
\tPCB Footlprint t{PCB Footlprint }
照着前面的格式添加即可,注意前面有个t
另外open in excel 打勾,用excel打开然后另存
十 五,输出网表
第1和3可以用于allegro, 另外是pads和AD的网表。
目录
三次握手和四次挥手
三次握手
四次挥手
setsockopt
Log.hpp
Sock.hpp
main.cc
TCP通信的时候,客户端发送信息既不能太快也不能太慢,如何保证发送方发送数据既不快又不慢呢?
服务器把自己的同步接收能力告诉客户端,而服务器的接收能力又由什么决定?接收缓冲区中剩余空间的大小。
根据对方接收能力,控制数据发送速度,这种策略叫流量控制。16位窗口大小就是接收缓冲区剩余空间大小。16位窗口大小中填的是自己的接收缓冲区大小。
这是TCP报头当中的6个标记位
6个标记位:是按照1个比特位表示某种含义的,为什么需要多个标记位?
我们可能会给对方发送各种类型的TCP报文。服务端会收到大量的不同的报文,这些标记位的本质就是来标记报文类型的。利用标记位区分报文类型。
各个标记位都是什么含义? SYN:该报文是一个连接请求报文。
FIN:该报文是一个断开连接请求的报文。 ACK:确认应答标志位,凡是该报文具有应答特征,该标志位都会被设置为1,大部分网络报文ACK都是被设置为1的。第一个连接请求报文不会被置为1.
三次握手和四次挥手 三次握手 1.如何理解连接?
因为有大量的client将来可能连接server,所以server端一定会存在大量的连接,OS管理这些连接的方式:先描述,再组织。
所谓的连接:本质其实就是内核的一种数据结构类型,建立连接成功的时候,就是在内核中创建对应的连接对象。再对多个连接对象进行某种数据结构的组织,对连接的管理也就成了对某种数据结构的增删查改。
维护连接是有成本的:内存+CPU资源。
2.如何理解三次握手?
握手的时候发的全是报文,甚至可能携带数据。并不仅仅是标志位,只不过是标志位被置为了1.
客户端发送SYN的时候,客户端的状态是SYN SENT,服务端收到一个请求而且将自己的SYN+ACK发出了,服务端的状态就是SYN RCVD,SYN SENT和SYN RCVD都是宏,当数据发出后,客户端和服务端状态其实就是1.
客户端一旦收到SYN+ACK并且将ACK发出,客户端就认为连接建立好了。状态变为ESTABUSHED
服务端收到ACK,服务端对应的三次握手就完成了,连接就建立好了,状态也变为ESTABUSHED。
三次握手期间有一个隐形的成本就是时间,未来收的时候一定晚于发送的时候。
三次握手对客户端和服务端都要起效。必须保证双方各自通信了三次
三次握手不一定要保证成功。只能保证较大概率握手成功,如客户端发送,服务器关机了。而且三次握手时,前俩次都是有应答的,最后一次客户端发出去之后没有应答,所以对于最后一次数据是否发送成功,客户端无法知晓。
如果最后一次报文丢失了,客户端只要把报文经过ACK发出,自己的状态就变为了ESTABUSHED,即客户端认为连接建立好了,但实际上,服务端可能会没收到这条消息。
1.为什么要三次握手?而不是一次,俩次,四次?
如果是一次握手,客户端可能会一次性给服务器发送大量的SYN,由于维护连接是由成本的。有可能会一次性把服务器整崩溃,一次发送大量SYN,叫做SYN洪水。
如果是俩次握手,客户端给服务端发消息,服务端给客户端返回SYN+ACK,俩次握手,服务器无法保证自己发送的SYN+ACK被对方收到,也无法感知,而服务器一旦发送处去SYN+ACK就认为自己的连接成功了,如果服务器一开始收到了大量的SYN,服务器再发送SYN+ACK,这就会导致服务器挂了大量的连接。又跟一次握手一样。
三次握手,当客户端发送最后一次ACK的时候,只要客户端把ACK发出了,就认为连接建立好了,服务器必须得收到ACK,保证三次握手完成才建立连接。如果一开始发送大量得SYN请求时,一次和俩次握手(俩次握手会出现服务器发送SYN+ACK时,客户端直接将SYN+ACK丢弃)都是服务器挂满了大量连接,而客户端可能会出现甚至没连接得情况。三次握手,服务器上有连接时,客户端必须建立好连接,服务器的连接数和客户端的连接数是等价的。三次握手以最小的成本在建立连接时,不会过度消耗服务器资源。当服务器上有连接时,客户端必须维护好连接。如果客户端攻击服务器,服务器上的连接数和客户端上的连接数一定是等价的,即俩者的资源损失是一样的。
三次握手并不能很好的保证安全问题。
通过三次握手,服务端可以嫁接同等的成本给client,验证全双工。
如果是四次握手,最后一次握手一定是服务端给客户端发的,当客户端直接丢弃最后一次ACK,此时所有的连接又都由服务端承担。
奇数次握手最后的成本都在客户端, 偶数次握手连接建立时成本都在服务端。
在握手时,尽量选择奇数次握手,的握手的目的在于把成本加在客户端,验证全双工,没必要执行五次,其次握手。
当三次握手,客户端最后一次发送ACK后立马发送数据,由于丢包服务端没收到ACK,此时客户端认为连接建立成功,一旦发送消息,由于三次握手没成功,服务端看到数据后,意识到了连接建立异常,服务器就立马给客户端回复一个报文,这个报文就是TCP报头,并且将标记位RST置为1.客户端此时关闭连接,重新开始三次握手。
RST:reset,连接重置。
RST: 对方要求重新建立连接; 我们把携带RST标识的称为复位报文段。
连接建立好了,如果对方发送消息,而我们的窗口大小是0,此时对方就不能发数据了,对方只能等,等到我们缓冲区有空间了,再继续发送消息。但如果我们缓冲区一直满,对方也不能一直等,发送方此时会设定PSH标志位。
PSH:督促对方尽快向上交付数据。
PSH: 提示接收端应用程序立刻从TCP缓冲区把数据读走。
因为TCP是具有按序到达机制的(优点),我们发送的时候,被对方上层读取到,必须得有先后顺序,如果想插队呢?
URG:紧急标志位,要配合报头中的16位紧急指针(特定的数据在有效载荷位置的偏移量),该指针所指的地方只有一个字节被称为紧急数据。
URG: 紧急指针是否有效。
四次挥手 如何理解四次挥手?
FIN是断开连接的标志位。当某一方要断开连接时,让FIN置1,把报文发给对方。而且这一方向另一方再也不会发送有效数据了。
ACK和FIN也可以被同时设置,服务器可以将ACK和FIN压缩在一起,即四次挥手可能会变成三次挥手。
断开连接就一定能成功吗?
也不一定,客户端首次发出断开连接的请求时,客户端会进入FIN_WAIT_1状态,服务端收到FIN之后给对方进行ACK,服务端会进入CLOSE_WAIT状态,客户端收到后进入FIN_WAIT_2状态。之后服务器发出FIN,状态变为LAST_ACK,客户端一收到FIN并且给对方ACK,客户端进入TIME-WAIT状态,服务端收到最后的ACK进入CLOSED状态。
CLOSE_WAIT时连接没关,因为四次回收没完成。如果服务器有大量的CLOSE_WAIT状态的连接的时候,原因是没有发FIN,即服务器引用层写的有BUG,忘了关闭对应的连接sockfd。
我们写一个简单的程序,并且不关闭sockfd
我们再用另一台机器访问
Measurement Studio是Microsoft Visual Studio的扩展软件,提供了用于创建测试和测量应用程序的.NET工具。
了解Measurement Studio的功能
Measurement Studio是唯一一款.NET工具套件,专为在Microsoft Visual Studio中构建工程应用,主要用于采集、分析并显示测量数据。您可以使用与硬件采集数据类型兼容的工程UI控件,清晰明了地展示数据。Measurement Studio具有高级且直观的面向对象硬件类库,简化了硬件通信的复杂性。您可以使用业界最快、最灵活且最适合将测量数据存盘的格式TDMS,将自定义信息添加到采集的数据中。您还可以对采集的信号进行实时在线分析,而无需艰难地编写自定义解析算法。 使用Measurement Studio工程UI控件,开发沉浸式Windows应用程序,重新定义您的用户体验。
无论采用何种方法采集数据,您均可使用支持所用开发语言的高层界面来编程硬件。
500多个分析函数任您选择,包括曲线拟合、频谱分析、数据统计和可视化,帮助您更好地理解数据。
Measurement Studio各版本旨在扩展Microsoft Visual Studio的功能,从而满足工程师的用户界面、硬件连接和数据分析需求。选择适合您的版本,满足.NET开发需求,也可选择购买包含Measurement Studio的软件套件
NI提供的硬件、软件产品及相应服务,能够帮助您深入解析数据的含义,并做出有据可依的业务决策。我们的产品线用途上自桌面设计、原型验证,下至全自动化生产测试系统,包罗万象。
Measurement Studio包括⽤于显⽰数据的⽤户界⾯控件,例如波形图控件,以及⽤于在⽹络上的应⽤程序之间传输实时测量数据的⽹络变量功能 measurement studio是一款相当专业的Microsoft Visual Studio的扩展软件,可以帮助用户在开发应用程序以及开发硬件的时候提供辅助功能,内置多种控件,可以直接加载到你的开发界面使用。目前增加了企业分析类库,用于频谱测量、线性代数、统计、曲线拟合等功能,能够适合于高级数据分析应用,并拥有标准版、专业版和企业版三大版本,其中企业版功能最强,拥有标准版和专业版所有的功能。该软件提供了用于创建测试和测量应用程序的.NET工具,是专为Microsoft Visual Studio中构建工程应用以进行测量数据采集、分析和显示而开发,用户可以使用与硬件采集数据类型兼容的工程UI控件,清晰明了地展示数据
openFeign介绍 OpenFeign是一种声明式、模板化的HTTP客户端(仅在Application Client中使用)(称OpenFeign作用:声明式服务调用)。声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操作远程http请求。
一 服务方操作 1 添加依赖 添加了Spring Boot和Spring Cloud版本声明。
添加了web环境和eureka client依赖
2 编写配置 必须要有应用程序名,因为OpenFeign是通过应用程序名进行调用。
spring.application.name=applicationservice 二 客户端操作 1 添加依赖 比application service项目多了openfeign的依赖
2 编写配置 spring.application.name=applicationclient server.port=8081 3 新建OpenFeign接口 OpenFeign接口命名:
调用应用程序+Feign
新建了com.bjsxt.feign.ApplicationServiceFeign。
注意:
@FeignClient 参数要写调用的Application Service的应用程序名
@RequestMapping中值要和需要调用的控制器方法URL相同
方法返回值要和调用控制器方法返回值相同。
方法名称随意,没有要求。
@FeignClient("APPLICATIONSERVICE") public interface ApplicationServiceFeign { @RequestMapping("/service1") String suiyi(); } 4 调用 在实现类中直接注入OpenFeign接口对象即可。没有在启动类上添加@EnableFeignClients时此处可能会报编译错误。
三 OpenFeign访问带有参数的控制器 1 简单参数applicationclient中Feign接口添加方法 @RequestParam注解必须有
如果Feign接口方法参数名和调用控制器参数名相同可以省略@RequestParam的参数。
@RequestMapping("/service2") String suiyi2(@RequestParam("name") String name123,@RequestParam int age) 2 传递请求体数据 如果Feign接口中方法参数没有写注解,表示把该参数值设置到请求体中,在Application Service方参数必须添加@RequestBody接收。
但是由于请求体数据特性,Feign接口方法最多只能出现一个不带有注解的参数。否则出现违法状态异常。
@RequestMapping("/service3") public String service3(@RequestBody Map<String,Object> map){ System.
如果你是一个网页小说的爱好者,并且想要把你最喜欢的小说下载到电脑上,那么Python就是一个非常好的工具。在这篇文章中,我们将介绍如何使用Python的requests库和BeautifulSoup库来编写一个简单的网页小说下载器。
准备工作 首先,我们需要确保Python环境已经安装了requests和BeautifulSoup库。你可以通过Python的包管理器pip来进行安装:
pip install requests beautifulsoup4 requests库是一个用于发送HTTP请求的库,BeautifulSoup库是一个用于解析HTML和XML文档的库。
编写下载器 下面是一个简单的Python脚本,用于下载网页小说:
import requests from bs4 import BeautifulSoup # 小说的URL url = 'https://www.example.com/novel/' response = requests.get(url) soup = BeautifulSoup(response.text, 'html.parser') # 获取小说的章节链接 chapter_links = [a['href'] for a in soup.select('a.chapter')] for link in chapter_links: # 获取每一章的内容 chapter_response = requests.get(link) chapter_soup = BeautifulSoup(chapter_response.text, 'html.parser') chapter_text = chapter_soup.select_one('div.chapter-content').get_text() # 将章节内容写入文件 with open('novel.txt', 'a', encoding='utf-8') as f: f.write(chapter_text + '\n') print('小说下载完成。') 在运行这个脚本之前,你需要将url变量替换为你想要下载的小说的链接。此外,可能需要调整获取章节链接和章节内容的代码,以适应具体的网站结构。
这个脚本首先会访问小说的主页,并解析出所有的章节链接。然后,对每一个章节链接,脚本会访问该链接,并解析出章节的内容。最后,将章节的内容添加到一个文本文件中。
注意事项 不同的网站可能有防爬虫策略,因此这个脚本可能无法在所有网站上运行。此外,未经许可的爬取和下载可能违反网站的服务条款,请在合法和道德的范围内使用这个脚本。
1. gcc 编译器编译的完整流程,分别有什么作用? gcc 编译器编译的完整流程有四步,分别是 预处理、编译、汇编、链接 预处理 :处理源文件中的 #ifdef 、 #include 、 #define 等预处理命令,该阶段会生成一个中间文件 .i gcc - E hello.c–o # 可以使用 -E 选项生成 .i 文件 编译 : gcc 把预处理后的结果编译成汇编语言代码,输入的是 .i ,编译后生成汇编语言文件 .s gcc - S hello.i –o hello.s 汇编 :编译器把编译出来的汇编语言汇编成具体 CPU 上的目标代码(机器代码)。输入汇编代码文 件 .s ,输出目标代码文件 .o 或 .obj。 gcc – c hello.s –o hello.o 链接 :把多个目标代码模块链接成一个大的目标代码模块。输入目标代码文件 .o (与其它的目标 代码文件、库文件、引导代码),汇集成一个可执行的二进制代码文件。 gcc hello.o –o hello 2. 什么是回调函数? 回调函数就是一个通过函数指针调用的函数。所以当一个函数作为参数使用的时候 , 这个函数就是 回调函数。 3.
单点部署 (1)下载zookeeper
wget https://dlcdn.apache.org/zookeeper/zookeeper-3.8.1/apache-zookeeper-3.8.1-bin.tar.gz (2)解压软件包
tar xf apache-zookeeper-3.8.1-bin.tar.gz -C /oldboyedu/softwares/ (3)配置环境变量 [root@elk101 ~]# cat /etc/profile.d/zk.sh #!/bin/bash export ZK_HOME=/oldboyedu/softwares/apache-zookeeper-3.8.1-bin export PATH=$PATH:$ZK_HOME/{bin} [root@elk101 ~]# source /etc/profile.d/zk.sh (4)创建配置文件
[root@elk101 ~]# cp /oldboyedu/softwares/apache-zookeeper-3.8.1-bin/conf/{zoo_sample,zoo}.cfg (5)启动zookeeper服务
[root@elk101 ~]# zkServer.sh start # 启动zookeeper服务 [root@elk101 ~]# zkServer.sh status # 查看zookeeper服务状态 [root@elk101 ~]# zkServer.sh stop # 停止zookeeper服务 [root@elk101 ~]# zkServer.sh restart # 重启zookeeper服务 (6)确定zookeeper服务后,测试zookeeper服务是否可用
[root@elk101 ~]# zkCli.sh .... [zk: localhost:2181(CONNECTED) 0] ls / [zookeeper] [zk: localhost:2181(CONNECTED) 1] zookeeper集群部署 1.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</head>
<!-- 注意:style和script都包含在body内部,否则会导致代码无样式效果以及js事件无法实现 -->
<body>
<div id="jsi-particle-container" class="container">
<!-- 创建画布 -->
<canvas width="100%" height="100%" style="align:center;"></canvas><!--canvas标签定义图形,必须使用脚本来绘制图形-->
</div>
<style>
html,body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden; /*overflow属性指定如果内容溢出一个元素的框,会发生什么 其属性值hidden表示内容会被修建,并且其余内容是不可见的*/
/* overflow属性值:
visible 默认值,内容不会被修剪,会呈现在元素框之外
hidden 内容会被修剪,并且其余内容是不可见的
scroll 内容会被修剪,但是浏览器会显示滚动条以便查看其他内容
auto 若内容被修剪,则浏览器会显示滚动条
inherit 规定应该从父元素继承overflow属性的值
注意:overflow属性只工作于指定高度的块元素上
*/
}
.container{
width: 100%;
height: 100%;
margin: 0;
padding: 0;
background-color: #000000;
}
</style>
<script>
首先,我们需要连接到数据库。我们可以使用PHP的mysql扩展来连接到MySQL数据库。以下是一个简单的代码示例:
<?php // 连接到数据库 $conn = mysql_connect("localhost", "username", "password"); // 选择数据库 mysql_select_db("mydatabase", "connection_link_identifier"); ?> 在这个例子中,我们首先使用mysql_connect()函数连接到本地MySQL服务器,并传递用户名和密码作为参数。然后,我们使用mysql_select_db()函数选择要使用的数据库。请注意,“connection_link_identifier”是一个可选参数,如果我们省略它,则使用默认值。
一旦我们连接到数据库,我们可以执行SQL查询并检索数据。以下是一个简单的代码示例:
<?php // 连接到数据库 $conn = mysql_connect("localhost", "username", "password"); // 选择数据库 mysql_select_db("mydatabase", "connection_link_identifier"); // 执行查询 $result = mysql_query("SELECT * FROM customers", $conn); // 输出结果 while ($row = mysql_fetch_assoc($result)) { echo "Name: " . $row['name'] . ", Age: " . $row['age'] . "\n"; } ?> 在这个例子中,我们执行一个简单的SELECT查询,检索customers表中的所有数据。结果存储在$result变量中。然后,我们使用mysql_fetch_assoc()函数从结果中逐行检索数据,并将其输出到屏幕上。
当然,这只是一个简单的例子,实际上查询可能涉及更复杂的SQL语句和数据操作。但是,希望这个例子能够帮助你开始学习PHP中的数据库操作。如果你需要更多的帮助,可以查看PHP文档或者在互联网上搜索更多的资源。
当您精通了基本的数据库操作后,可以开始学习更高级的主题,例如:
Active Record
Active Record是一种常见的数据访问模式,它提供了一种将PHP应用程序与数据库联系起来的标准方式。Active Record通过提供一个简洁的接口,使您能够轻松地执行数据库操作,例如查询、插入、更新和删除数据。以下是一个使用Active Record的示例代码:
<?php class Customer extends ActiveRecord\Model { static $table_name = 'customers'; } // 查询所有客户 $customers = Customer::find(); // 查询一个特定客户 $customer = Customer::find_by_id(1); // 插入新客户 $customer = new Customer(); $customer->name = 'John'; $customer->email = 'john@example.