Vue修改数组、对象并且触发视图更新的方法以及原理

一、数组 items: ['a', 'b', 'c'];//一个普通的数组 this.items[1] = 'x' ;//修改已有项 this.items[3] = 'd' ;//新增一项 this.item.length = 2;//修改数组的长度 //一个对象数组 msg: [{id: 1,selected: true, title: 'aaa',}, {id: 2,selected: false, title: 'bbb'}, {id: 3,selected: true, title: 'ccc'}] this.msg[0] = { id : 1,selected : true, title : 'AAA'} //修改已有项 this.msg[3] = { id : 4,selected : true, title : 'DDD'} //新增一项 this.msg[0].child = "Child";//给数组的某一项新增属性 像上面这样,直接通过数组的下标去新增、修改数组的某一项、修改数组的长度,这些操作都不会被vue检测到 —— 数组的值虽然发生了变化,但是页面不会更新。 解决方案: 方法详解 Array.splice(index,num,newItem) Array 要操作的数组 index 要删除元素的下标 num 要删除元素的个数(num=0则不删除) newItem 删除元素后想要在原位置替换的值(可以是0个或者多个) this.

python爬取小说以及数据分析

from pyecharts import options as opts from pyecharts.charts import Bar, Grid, Line, Liquid, Page, Pie from pyecharts.commons.utils import JsCode from pyecharts.components import Table from pyecharts.faker import Faker import requests from bs4 import BeautifulSoup import csv header={"User-Agent":"Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36 Edg/112.0.1722.48"} for i in range (1): URL="https://www.qidian.com/rank/readindex/page{}/".format(i) resp=requests.get(URL) soup=BeautifulSoup(resp.content,"html.parser") big_div=soup.find("div",attrs={"class":"rank-body"}) #名字 name=[] names=big_div.find_all("h2") for i in names: n=i.text name.append(n) # print(name) #小说类型 lx=[] lxs=big_div.

matlab绘制局部放大图

先给出一个普通图代码: N=20000; i=1:1:N; a=sqrt(100)*randn(1,N/4); b=randn(1,N); c=[a,b]; h1=plot(i,c(i),':.m','LineWidth',0.7); legend(h1,'signal') xlabel('t/s');ylabel('signal'); xlim([0,20000]); % 设置坐标轴范围 ylim([-40,80]); title('signal') 运行如下: 现在开始进行局部放大,假设我要放大10000~12000这一区间的图形。 首先点击箭头标志,选中图片 选中后ctrl+c进行复制,然后ctrl+v进行粘贴,将粘贴后的图片移动并缩放到合适位置,如下图所示: 然后点击编辑标志,选中小图部分 再点击工具图标,选中放大 然后就可以开始滚动鼠标轮在小图中放大你想要放大的内容,期间可以选择平移图标,将图片内容平移到你想要的位置。 放大结果如下: 这里选中了小图中一些没有用的元素(图例等),并进行了删除,使得局部放大图更为简洁 最后再将大图需要局部放大的部分与局部放大图对应起来。首先按如下标记打开绘图编辑工具栏 然后选中插入矩形标记: 然后在大图中将你放大的部分圈起来,如下: 再选中箭头标记,将局部放大图与需要放大部分对应起来: 效果如下: 最后可以更改一下边框颜色和箭头颜色以及线型。先依次选中我们要更改颜色的部分,然后点击颜色标记 效果如下: 为了让图更加美观一点,我们可以加粗矩形框和箭头的线宽,方法就是先选中矩形框(箭头),然后右击,选中线宽,这里将线宽更改为1.0: 效果如下: 在上述线宽的选项下,我们可以设置线型,这里全部设置为虚线,效果如下: 最终局部放大图处理完毕

(三)ChatGLM-6B 的 DeepSpeed/P-Tuning v2微调

文章目录 模型文件和相关代码准备ChatGLM6B部署解决`ninja`报错 训练开始 模型文件和相关代码准备 安装日期:2023-04-19 模型文件地址:https://huggingface.co/THUDM/chatglm-6b/tree/main Hash: 35ca523 相对上一篇文章(04-09),官方更新了文件,也增加了 DeepSpeed支持,所以火速跟进体验一下(他们也好努力,截图3小时前还在更新代码) 参考之前写的(二)ChatGLM-6B模型部署以及ptuning微调详细教程 关于附:下载大文件的的python代码 ,准重新下载模型文件(国外,速度慢没办法) 等待模型文件下载完毕后,下载其他的配置文件,把大的模型文件移动进去 # 根据需要选择一个目录存放模型文件 mkdir /data/thudm2/ cd /data/thudm2/ # 准备下载其他配置文件 GIT_LFS_SKIP_SMUDGE=1 git clone https://huggingface.co/THUDM/chatglm-6b # 移动文件进去,存在覆盖即可(上面代码的占位文件,其实是没用的,覆盖了) mv -f pytor* chatglm-6b/ mv -f ice_text.model chatglm-6b/ ChatGLM6B部署 准备代码 https://github.com/THUDM/ChatGLM-6B hash 01e6313 git clone https://github.com/THUDM/ChatGLM-6B.git cd ChatGLM-6B # 把模型提前准备进来,这里的路径需要根据实际情况修改,你的未必和我一样 ln -s /data/thudm2/ THUDM 修改requirements.txt, 特别注意torch torchvision版本对应问题,看官网 protobuf==3.20.0 transformers==4.28.0 cpm_kernels gradio mdtex2html sentencepiece rouge_chinese nltk jieba datasets deepspeed accelerate torchvision==0.14.0 torch==1.13.0 我的显卡环境

计算机网络基础 第三章练习题

计算机网络基础 第三章练习题 现在大量的计算机是通过诸如以太网这样的局域网连入广域网的,而局域网与广城网的互联是通过( A)实现的。 A. 路由器B. 资源子网C. 桥接器D. 中继器 下列不属于数据链路层功能的是(B )。 A. 帧定界功能B. 电路管理功能C. 差错控制功能D. 流量控制功能 数据链路层是OSI模型中的第二层,主要负责将数据包装成帧并在物理媒介上传输。其主要功能包括: 帧定界功能:将数据分成适当的大小并打上帧头和帧尾。 差错控制功能:检测和纠正传输中发生的位错误。 流量控制功能:控制数据的流量,防止接收方无法处理过多的数据。 访问控制功能:协调多个设备对物理媒介的使用。 对于信道比较可靠且对实时性要求高的网络,数据链路层采用(A )比较合适。 A. 无确认的无连接服务B. 有确认的无连接服务C. 无确认的面向连接服务D. 有确认的面向连接服务 下述协议中,(A )不是链路层的标准。 A. ICMP B. HDLC C. PPP D. SLIP ICMP(Internet Control Message Protocol,互联网控制报文协议)是一种网络层协议,它是IP(Internet Protocol,互联网协议)的附属协议,用于在IP主机、路由器之间传递控制消息和错误报告。 而 HDLC(High-level Data Link Control,高级数据链路控制协议)、PPP(Point-to-Point Protocol,点对点协议)和SLIP(Serial Line Internet Protocol,串行线路互联网协议)都是链路层的标准协议,用于在两个物理设备之间建立可靠的数据传输连接。其中,HDLC是ISO制定的数据链路层协议,PPP和SLIP则是TCP/IP协议族中的链路层协议。 假设物理信道的传输成功率是95%,而平均一个网络层分组需要10个数据链路层帧来发送。若数据链路层采用了无确认的无连接服务, 则发送网络层分组的成功率是(B ). A. 40%B. 60%C. 80%D. 95% 假设物理信道的传输成功率为0.95,则传输失败的概率为0.05。由于采用了无确认的无连接服务,发送端发送的每个数据链路层帧在发送后不会等待接收端的确认,因此如果其中任何一个帧在传输过程中出现错误,发送端都不会得到任何通知。因此,对于一个网络层分组,只有在所有的数据链路层帧都传输成功的情况下,才能认为该网络层分组发送成功。 由于每个网络层分组需要发送10个数据链路层帧,因此该网络层分组发送成功的概率为: 0.95^10 = 0.5987 因此,发送网络层分组的成功率约为 59.87%,即选项 B 60%。

视觉SLAM:模型介绍、算法框架及应用场景

作者:张长鸿 湖南大学 校稿:董亚微 编辑:郑欣欣@一点人工一点智能 原文地址:视觉SLAM:模型介绍、算法框架及应用场景 目录 01 什么是SLAM 1.1 相机模型 1.2 相机运动 1.3 建图 02 SLAM算法框架 03 SLAM的应用场景 3.1 自动驾驶的高精度定位 3.2 自主移动机器人 知识扩展: 组合导航(GNSS/INS) 二维码导航/磁导航 3.3 室内场景的三维重建:AR(增强现实技术)等 04 结语 参考文献: 本文主要想使用尽量少的专业词汇来解释清楚视觉SLAM是如何进行定位的(在某些表述上可能并不严谨),希望对视觉SLAM有兴趣的伙伴能在刚接触SLAM时有个基本的了解,本文同时介绍了视觉SLAM的经典框架和应用场景。想要深入学习的伙伴,还请参考更专业更系统的书籍和文献。 01 什么是SLAM SLAM(Simultaneous Localization and Mapping),也就是同时定位与地图构建,它是指搭载特定传感器的车辆、无人机等移动机器人,在没有环境先验信息(什么是先验信息?可以自己查一下)的情况下,在运动过程中,估计自己的运动状态,同时建立环境模型的一系列任务。 目前大家接触比较多的,已经将SLAM技术应用于实际生活中的,就是扫地机器人了。我们来想一下:扫地机器人来到一个陌生的环境后,是怎样去清扫一个垃圾呢?一个直观的想法就是机器人先确定自己的位置,然后确定垃圾相对于自身的位置,这样就有了一个起点和终点,机器人只需要从起点移动到终点就能清扫这个垃圾了。但是这是很直观的想法,而这个想法的前提是:我们清楚房间的地图构造,这样我们才能更好地完成垃圾清扫的任务。所以扫地机器人需要完成的流程应该是:了解自己周围的环境,构建房间地图,确认自己与垃圾的位置,然后规划路线,移动过去,完成清扫。而这整个流程中,构建地图、进行自身的定位,就是咱们SLAM的主要任务了。 通过这样一个小例子,就可以体现出SLAM的作用,通俗地讲,SLAM要解决的主要是两个问题: 1. 我在什么地方?----定位 2. 周围环境是什么样? ----建图 而根据传感器类型的不同,SLAM可以分为不同的类型,如表1所示 表1 SLAM类型 本文主要介绍的就是以相机为传感器的视觉SLAM。视觉SLAM是根据一张张连续输入的图像,从中推断相机的运动,以及周围环境的情况。接下来将介绍相机模型和相机运动,我们将看到相机模型是如何利用已知的图像信息构造观测方程,并从观测方程解出相机运动,而获取相机运动后,到此也就完成了定位。我们先从相机模型开始,一步步推导到最后完成定位。 1.1 相机模型 相机的成像模型表示的是一个真实世界中的三维点到图像二维像素点的对应关系,即相机视野中的三维点可以在图像上找到对应的像素点,在不考虑畸变的情况下,单目相机成像的理想模型为针孔模型,如图1所示,光心O即镜头的中心,光轴即经过光心与物理成像平面垂直的直线,f代表焦距,即针孔到物理成像平面的距离,代表在相机坐标系下任意的三维空间点,经过光心,投影到二维物理成像平面中点,每个三维空间点对应物理成像平面上的一个像素。 针孔模型通过成像过程中的几何关系建立三维世界到二维像素平面的映射关系,在数学上的描述就是一个函数关系式,即 ,也称之为观测方程。其中,二维像素坐标,三维空间点坐标P,K为相机内参矩阵,由相机自身的特性决定。 图1 相机成像模型 图2 三维空间的坐标变换 1.2 相机运动 了解相机运动之前,需要先了解几个基本概念: 世界坐标系:在视觉SLAM中,通常把拍摄第一张图像时的相机坐标系指定为世界坐标系,在被指定后不变且唯一,可以将世界坐标系理解为笛卡尔坐标系中的原点。 相机坐标系:以相机的光心(小孔)作为原点的坐标系,其随相机的移动而发生变化。 相机的运动是刚体运动,刚体运动的坐标变换可由一个旋转矩阵(R)和一个平移向量(t)表示,考虑一个三维空间点P,P点在世界坐标系下的观测值为,在相机坐标系下的观测值为,点P在不同坐标系下的观测值转换关系如下所示: 通过以上内容的介绍,我们就可以按照以下几个步骤了解定位是如何完成的: (1)视觉SLAM系统输入的信息是不同时刻的相机图像,我们所要利用的就是图像的像素信息,假设在第一帧坐标系下,已知某一个空间点,在第一帧图像和第二帧图像上的成像点分别是。 (2)通过相机模型,可以得到如下两个观测方程,和代表着第一帧坐标系到第二帧坐标系的旋转和平移 。 (3)可以根据8个这样的匹配点对,求解上述方程,得到。 (4)即代表着两个坐标系的转换关系,通常情况下,第一帧坐标系将被定为世界坐标系,由于世界坐标系是固定不变的,因此就可以得到第二帧相机坐标系的位置和姿态,也即完成了定位,定位也就是获得任意时刻的相机坐标系相对于世界坐标系的位置和姿态。

大文件上传

单个文件直接上传 1、前端根据input组件的upload功能唤起文件管理器,然后选择文件,日常文件上传类型一般有两种 :以base64字符串上传(使用fileReader对象获取文件的base64字符串) :以二进制流文件上传(使用formDate模拟form表单上传) 2、后端根据文件的类型来判别或者进行对应的逻辑处理 3、接口返回成功标识,如果有需要会显示网络链接 base64格式 是一种基于64个可打印字符来表示二进制数据的表达方法,常用语处理文本数据的场合,表示、传输、存储一些二进制数据 图片的base64编码就是将一张图片编码成一串字符串,使用该字符串可以代替图片地址,直接在浏览器打卡可以访问地址 formData格式 FormData参考文档: FormData - Web API 接口参考 | MDN formData就是将form表单元素的name和value进行组合,实现表单数据的序列化,从而减少表单元素的拼接,提高工作效率。 Web API 提供了FormData方法,提供了一种表示表单数据的键值对的构造方式,通过FormData.append(key, value)向FormData中添加新的属性值。 前端 <!-- 上传 --> <el-upload class="upload-demo" drag action="http://localhost:300/pc/upload" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" :before-upload="parseFile" :http-request="upload" :data="additionalData" > parseFile(file) { this.additionalData = { type: "test" }; return new Promise((resovle) => { this.$nextTick(() => { resovle(true); }); }); }, upload(e) { console.log(e); let formData = new FormData(); formData.append("file", e.file); formData.append("type", "test"); this.$myrequest({ url: "

Linux的两种软件安装方式(大数据学习)

1、Yum源配置 使用yum命令进行软件安装是linux安装文件的一个重要部分。 yum install -y 软件的名字 -- -y 一路yes //它会通过一个yum源配置的网址进行软件的下载,并安装 -- yum 源默认的网址是国外的,所以,一般修改yum源为国内的。将yum源地址修改为国内的aliyun。 -- 修改阿里云的镜像文件: -- 1、cd /etc/yum.repos.d/ -- 2、备份⼀下:cp CentOS-Base.repo CentOS-Base.repo.bak -- 3、下载阿⾥云镜像到本地: curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo -- 4、清除yum的缓存 yum clean all yum makecache -- 5、yum install -y ntpdate //检测aliyun的镜像安装成功没 注:yum search ifconfig 用于查看某个命令是哪个安装包下的命令 -- eg:发现net-tools.x86_64 软件中包含了这个命令,所以应该安装这个软件才对。 yum install -y net-tools.x86_64 -- 注:使用这个命令 ifconfig == ip addr 如果是在windows电脑上,ipconfig 用于查看windows上的ip地址 -- 软件的升级 yum -y update 软件的名字 -- 卸载 yum -y remove 软件的名字 注:yum源安装本质上也是rpm安装,因为它是先将rpm 安装包下载下来之后,又使用命令给你安装了一遍而已。

用fastjson把网络传输的字符串转换为java对象

这里举例一个网络传输来的字符串(json格式字符串) [{ “foodLangInfoVOList”: [{“name”: “soli”}], “menuFoodRelationVO”: {“amount”: “14”, “secUnitDesc”: “łyżeczki”}, “desc”: “płaskie” }, {“foodLangInfoVOList”: [{“name”: “wody”}], “menuFoodRelationVO”: {“amount”: “1500”, “secUnitDesc”: “null”}, “desc”: “null”}] 这里解释下: 上面是一个JSON格式的字符串,其中包含了两个对象,每个对象有三个属性,分别是 “foodLangInfoVOList”、“menuFoodRelationVO” 和 “desc”。其中 “foodLangInfoVOList” 和 “menuFoodRelationVO” 属性的值也是对象,它们分别包含了各自的属性和属性值。该字符串的具体含义需要根据上下文和业务场景进行解析,(这里用来app传输食材表,这篇文章无需关注这个) 可以看出上面的是个json数组字符串,这个jsonarray字符串里面中的每一个元素都有一个foodLangInfoVOList字段的数组,数组的第一个元素里包含name字段,包含一个key为menuFoodRelationVO的对象,该key的value中包含amount、secUnitDesc, 最后包含一个key为desc的字段。 JSON 格式的字符串是一种数据序列化的格式,用于数据的传输和存储,可以表示不同的数据结构,如对象、数组、字符串、数字等。在 Java 中,可以通过解析 JSON 字符串来得到对应的 JSON 对象 这里解释下,这个json字符串是我在ide中用输出函数打印的结果,真实网络传输中的json格式字符串是包含转义字符的,在控制台中打印JSON字符串时,通常会将其还原成原始的字符串形式,因此看不到转义字符。 转义字符 \ 是为了区分字符串中的特殊字符,如双引号 ", 换行符 \n, 制表符 \t 等。当我们直接打印一个字符串到控制台时,控制台会自动解析这些特殊字符,将其显示为其对应的字符,而不是转义字符本身。所以你在控制台打印看到的是字符本身,而不是转义字符。 将这个网络传输的字符串转换为java对象 先贴java对象的代码, package com.chuyitech.gourmagic.device.vo; import java.util.List; /** * Created by sjx on 4/18/23 * tuya食材表 */ public class TuyaFoodInfoVo { List<FoodLangInfoVO> foodLangInfoVOList; MenuFoodRelationVO menuFoodRelationVO; String desc; //补充说明 public List<FoodLangInfoVO> getFoodLangInfoVOList() { return foodLangInfoVOList; } public void setFoodLangInfoVOList(List<FoodLangInfoVO> foodLangInfoVOList) { this.

安装配置 JupyterLab ubuntu20.04

目录 ​编辑 (1)安装 (2)配置 (1)生成配置文件 (2)生成jupyterlab的登录密码 (3)修改 jupyter 的配置文件 (4)安装 jupyterlab 插件 (3)启动 安装时保持software updater设置如下 (1)安装 sudo apt-get install libffi-dev sudo apt install python3-pip pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple jupyter pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple jupyterlab sudo apt install jupyter-core 安装jupyterlab时有warning WARNING: The scripts ... are installed in /home/.../.local/bin which is not on PATH. 参考后解决:(1条消息) WARNING: The scripts ... are installed in /home/.../.local/bin which is not on PATH. 警告之解决_香饽々的博客-CSDN博客 删干净jupyter pip uninstall -y jupyter pip uninstall -y jupyter_core pip uninstall -y jupyter-client pip uninstall -y jupyter-console pip uninstall -y notebook pip uninstall -y qtconsole pip uninstall -y nbconvert pip uninstall -y nbformat 为了避免安装时提示版本问题,一定添加清华源在命令行中,我个人的情况是不限定清华源会显示版本不匹配的问题 (2)配置 (1)生成配置文件 jupyter notebook --generate-config ​

搞定重复计数:Python 中的 Counter 模块

文章目录 参考描述Counter 模块Counter() 类Counter() 对象字典有序性KeyError魔术方法 \_\_missing\_\_ update() 方法 Counter 对象的常用方法most_common()elements()total()subtract() Counter 对象间的运算加法运算减法运算并集运算交集运算单目运算 Counter 对象间的比较>== 参考 项目描述Python 标准库DougHellmann 著 / 刘炽 等 译搜索引擎BingPython 官方文档collections — 容器数据类型 描述 项目描述Python 解释器3.10.6 Counter 模块 在 Python 的 collections 模块中,有一个很常用的模块就是 Counter。Counter 是一个简单的计数器,用于统计某些 可哈希对象 的数量。它以字典的形式存储元素和它们的计数。 Counter() 类 类 Counter() 能够对传入给该类的参数按照一定规则进行计数,并将计数对象与计数结果作为键值对以字典的形式进行结果的返回。 Counter(iterable=None, /, **kwds) 举个栗子 from collections import Counter # 返回一个空的 Counter 对象 cnt = Counter() print(cnt) # 将可迭代对象(字符串)作为参数 cnt = Counter('Hello World') print(cnt) # 将可迭代对象(列表)作为参数 cnt = Counter(['a', 'a', 'b', 'd', 'c', 'd']) print(cnt) # 使用可迭代对象(字典)作为参数 cnt = Counter({'a': 1, 'b': 2, 'd': 3, 'c': 2}) print(cnt) # 使用关键字参数 cnt = Counter(a=1, b=2, d=3, c=2) print(cnt) 执行效果

nodejs ubuntu20.04源码安装

运行jupyter的时候遇到报错,所以下载nodejs,apt下载的最高版本是10.19.0,所以选择源码安装 (Deprecated) Installing extensions with the jupyter labextension install command is now deprecated and will be removed in a future major version of JupyterLab. Users should manage prebuilt extensions with package managers like pip and conda, and extension authors are encouraged to distribute their extensions as prebuilt packages An error occurred. ValueError: Please install nodejs >=12.0.0 before continuing. nodejs may be installed using conda or directly from the nodejs website.

js UTC、GMT时间问题记录

参考链接 GMT、UTC、 时区、JavaScript Date总结Js中的GMT标准时间、UTC调和时间和北京时间,傻傻分不清 内容 时间格式:YYYY-MM-DDThh:mmZ,其中T表示时间的开始,Z表示时区。 UTC时间格式:2020-01-13T16:00:00.000Z,T表示分隔符,Z表示的是UTC。(相差北京时间8小时)对应的北京时间:2020-01-14 00:00:00。 GMT时间格式:2023-04-13T12:00+08:00。 在JS中使用new Date(),会自动转换成当前时区。 new Date() 如果想实现国际化,数据库可以采用存放时间戳的方式,因为没有时区的影响,都是从1970年01月01日00时00分00秒计算的时间。然后根据当前的地区来显示。

C++: 宏、const、vector向量、map、智能指针、多态封装继承

文章目录 一、预处理,宏内联函数和宏定义的区别 二、const, constexpr, static三、vectorvector和list的区别: 四、map五、智能指针六、多态、封装、继承 C++ 编译四个过程:预处理、编译、汇编、链接 一、预处理,宏 ifndef ifdef endif 分别是什么?什么作用? 这些都是预处理命令,预处理命令不是C++语言的组成部分,是在编译之间执行的。 C++提供三种预处理功能:宏定义、文件包含、条件编译。上面三个是条件编译的命令。 // 如果所指定的标识符已经被 #define 定义过,则只编译程序段1,否则编译程序段2. #endif 用来限制 #ifdef 命令范围 #ifdef 标识符 程序段1 #else 程序段2 #endif // n代表not,作用与上述逻辑相反 #ifndef 标识符 程序段1 #else 程序段2 #endif 内联函数和宏定义的区别 内联函数在编译时展开,而宏在预编译时展开在编译的时候,内联函数直接被嵌入到目标代码中去,而宏只是一个简单的文本替换。内联函数可以进行诸如类型安全检查、语句是否正确等编译功能,宏不具有这样的功能。宏不是函数,而inline是函数宏在定义时要小心处理宏参数,一般用括号括起来,否则容易出现二义性。而内联函数不会出现二义性。 C++ inline函数 inline函数一般用于比较小的,频繁调用的函数,这样可以减少函数调用带来的开销。只需要在函数返回类型前加上关键字inline,即可将函数指定为inline函数。 inline有点类似于宏定义,但是它和宏定义不同的是,宏定义只是简单的文本替换,是在预编译阶段进行的。而inline的引入正是为了取消这种复杂的宏定义的。 同其它函数不同的是,最好将inline函数定义在头文件,而不仅仅是声明,因为编译器在处理inline函数时,需要在调用点内联展开该函数,所以仅需要函数声明是不够的。 https://blog.csdn.net/u013321328/article/details/19838145 二、const, constexpr, static const关键字的作用?const和constexpr区别?const和static区别? const(constant):告诉编译器约束某个值不改变。在 C++ 中用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数。 被const修饰的变量变成常量,不能被再次赋值。不允许被修改。如果取它的地址再重新赋值,可能会发生意想不到的行为。在其前面再加 volatile,可以让编译器忽略 const的修饰。 // 举例:const修饰函数形参:https://blog.csdn.net/qxqxqzzz/article/details/127342899 函数参数为结构体时:地址传递减少内存(比如结构体有多个属性或成员),同时使用const修饰结构体指针形参防止误操作修改结构体属性 // void printS(student s) { // 值传递会拷贝数据占用内存 void printS(const student* s) { // 地址传递 // s->name = 'aa' // 错误:不允许修改 } void main { // printS(s); // 值传递 printS(&s); // 地址传递,如果函数形参不加const会导致外面main函数中结构体s的属性也被修改!! } constexpr: 使指定的常量表达式获得在程序编译阶段计算出结果的能力,而不必等到程序运行阶段。 C++ 11 标准中,constexpr 可用于修饰普通变量、函数(包括模板函数)以及类的构造函数。

编译livox ros driver2(ROS2、livox、rviz、ubuntu22.04)

1. 编译Livox-SDK2 官方地址:https://github.com/Livox-SDK/Livox-SDK2 执行一下命令: git clone https://github.com/Livox-SDK/Livox-SDK2.git cd ./Livox-SDK2/ mkdir build cd build cmake .. && make sudo make install 如上就安装完成了Livox-SDK2,会安装如下内容: -- Installing: /usr/local/lib/liblivox_lidar_sdk_static.a -- Installing: /usr/local/include/livox_lidar_def.h -- Installing: /usr/local/include/livox_lidar_api.h -- Installing: /usr/local/include/livox_lidar_cfg.h -- Installing: /usr/local/lib/liblivox_lidar_sdk_shared.so 如需删除,执行如下命令: sudo rm -rf /usr/local/lib/liblivox_lidar_sdk_* sudo rm -rf /usr/local/include/livox_lidar_* 2.编译livox_ros_driver2 官方地址:https://github.com/Livox-SDK/livox_ros_driver2 2.1.克隆源代码 打开终端执行如下命令,会将源代码clone在/home/ws_livox/src/livox_ros_driver2目录下,这步创建了ROS2需要使用的工作空间。 git clone https://github.com/Livox-SDK/livox_ros_driver2.git ws_livox/src/livox_ros_driver2 2.2.编译 终端进入到/src/livox_ros_driver2目录下,执行如下命令: source /opt/ros/humble/setup.sh ./build.sh humble 第一行命令是将基于Ubuntu22.04的ROS2 humble引入环境变量(如果已经配置了环境变量,则不需要执行这一步); 第二行命令是构建基于humble的ROS2下的livox_ros_driver2,读者可以根据自己的目标系统编译对应的驱动,详细命令可以参见官网内容; 2.3.配置文件说明 2.3.1.launch文件说明 首先根据传感器修改对应参数,笔者使用的是Livox-Mid360,读者可以根据自己的传感器修改对应参数文件。 Launch文件在 ws_livox/src/livox_ros_driver2/launch_ROS2 文件夹内,包括: 根据不同的应用场景,启动不同的节点和配置。

Qt Model/View结构原理之QAbstractTableModel基本使用

一、Model/View基本原理 GUI应用程序开发中往往少不了列表框,表格,树形结构等表现形式的应用。当然Qt中也提供了相应的视图类QListView,QTableView, QTreeView,这些类使用模型/视图Model/View架构来管理数据之间的关系及其呈现给用户的方式。这种体系结构引入的功能分离为开发人员提供了更大的灵活性来定制数据项的表示,并提供了一个标准模型接口,允许在现有的视图中使用广泛的数据源。 Data:是实际数据,可以数据库的一个数据表或SQL查询结果,内存中的StringList,或文件等等。 View:GUI界面组件,视图从数据模型获得每个数据线的模型索引(Model index),通过模型缩影获取数据,然后为界面组件提供显示数据。比如QListView,QTableView, QTreeView等。 Model:与实际数据通信,并为视图组件提供数据接口。可以理解成数据adapter,数据wrapper。它从原始数据提取需要的内容,用于视图组件进行显示和编辑。 这样设计的好处有: 通过Model/View使数据源与显示界面分离,代码解耦; 另外还可以将同一数据模型在不同的视图中显示; 还可以在不修改数据模型的情况下,设计特殊的视图。 Delegate:在model/view结构中,还提供了代理功能(Delegate),代理功能可以让用户定制数据的界面显示和编辑方式。 model,view,delegate之间使用信号和槽进行通信。当数据发生变化时,model通过信号通知view; 当用户在UI上操作数据时(选中,点击等),view通过信号表示这些操作信息; 当用户编辑数据时,delegate通过信号通知model和view编辑器的状态。 1.数据模型 Model QAbstractItemModel是所有数据模型的基类,这个类定义了view和delegate存取数据的接口。但原始数据不一定要存储在model里。 而通常情况是我们使用QListView,QTableView, QTreeView都会使用与之相应的模型类,分别继承自QAbstractListModel,QAbstractTableModel,QAbstractItemModel,生成自己定制的数据模型类。 2.视图组件 View 视图组件View就是显示数据模型的数据的界面组件,Qt提供如下常用视图组件: QListView:显示单列的列表数据,适用于一维数据的操作; QTreeView:显示树状结构数据,适用于树状结构数据的操作; QTableView:显示表格状数据,适用于二维表格型数据的操作。 视图类的setModel()函数,即可完成view和model的数据绑定,同时在view上的修改能自动关联到model。 3.代理 delegate 代理就是视图组件上为编辑数据提供编辑器,如在table组件中双击一个单元格编辑数据是,缺省是使用QLineEdit编辑框。代理的作用首先是从model中取数据,然后显示在编辑器中,修改数据后,又将其保存到model中。 通常使用需要派生自QStyledItemDelegate类,创建自定义代理类。 二、QAbstractTableModel使用 通过上面的分析,我们知道QAbstractTableModel,主要为QTableView提供数据模型接口,我们可以子类化该抽象类并实现相关接口。下面我们做一个简单9*9乘法口诀的demo来看一下具体使用方法: 必须要实现的接口如下3个: //返回行数 int rowCount(const QModelIndex &parent = QModelIndex()) const override; //返回列数 int columnCount(const QModelIndex &parent = QModelIndex()) const override; //根据模型索引返回当前的数据 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; 当然只有必须的3个接口,好像还不能很好的工作,首先我们需要给model赋初值。 新增setInitData成员函数,加载数据并刷新。 void MyTableModel::setInitData(QList<CellInfo*>& data) { //重置model数据之前调用beginResetModel,此时会触发modelAboutToBeReset信号 beginResetModel(); //重置model中的数据 m_datas = data; m_rowNum = ceil(data.

vue页面跳转传值和获取路径中的参数的两种形式

页面跳转传值: 1. 使用<router-link :to="'/saas-client/detail/'+scope.row.id"> 标签 在router.js中的path写法:path: 'detail/:id', 目标页面取值:this.companyId = this.$route.params.id; 2.使用:name – params传参数 - 地址栏看不到参数 this.$router.push({ name:'saas-client-detail', params:{id:row.id} }) 在router.js中的path写法:path: 'detail', 目标页面取值:this.companyId = this.$route.params.id; 3.使用:path – query 传参 - 地址栏可以看到参数 this.$router.push({ path:'/saas-client/detail', query:{id:row.id} }) 目标页面取值:this.companyId = this.$route.query.id 获取路径中的参数的两种形式 路径:http://localhost:3000/edit/123 取值123的方式:this.$route.params.id 路径:http://localhost:3000/?token=123 取值123的方式:this.$route.query.token

开源工具利器之基于主机的IDS:Wazuh

声明 好好学习,天天向上 好好跟着蜗牛学苑的邓强老师学习技术原理 官网 前身OSSEC https://www.ossec.net/ 现在已开源 https://wazuh.com/ https://github.com/wazuh 安装 基础 yum install curl unzip wget libcap net-tools 配置源 /etc/yum.repos.d/wazuh.repo [wazuh] gpgcheck=1 gpgkey=https://packages.wazuh.com/key/GPG-KEY-WAZUH enabled=1 name=EL-$releasever - Wazuh baseurl=https://packages.wazuh.com/4.x/yum/ protect=1 yum install wazuh-manager 或者官网有离线的rpm包,后续的agent也需要在官网下载 安装完后,启动 systemctl status wazuh-manager 介绍 服务器端安装了wazuh的服务后,服务自动就会采集本台服务器上的信息,服务器上不需要再装agent 默认目录为 cd /var/ossec/ active-response:响应的脚本 agentless:无代理安装,即用户名密码 etc:配置,ossec.conf核心配置文件 ruleset:自带规则库,建议不改 log:日志,预警核心 以下两个目录记录了何时、触发了哪些规则 /var/ossec/logs/alerts/alerts.json:json格式的预警信息,用于分析展示,这不就是给elk用于展示的嘛 /var/ossec/logs/alerts/alerts.log:适用于直接查看 初步感知 hids毕竟是基于主机的ids,所以监控的都是主机上的各种信息,文件夹或者命令执行结果等,看核心配置中的目录监控,可以看到监控了登录日志 /var/ossec/etc/ossec.conf 模拟登录失败,看看有什么反应 实时查看日志 tail -f alerts.log ssh到这台服务器上,输入错误密码 ssh root@192.168.174.5 可以看到触发了两条规则5557和5760 在这个文件里面看到5557规则 /var/ossec/ruleset/rules/0085-pam_rules.xml 这个文件是5760 /var/ossec/ruleset/rules/0095-sshd_rules.xml 当我们连续登录root,密码输错很多次次后报了一条5763 5763规则是如果5760触发,120秒内触发8次,就触发本条规则,描述就是怀疑暴力破解 配置了解 全局配置 /var/ossec/etc/ossec.

新版IDEA(2022.3)配置热部署

添加依赖 如果只有一个项目,直接在pom.xml里添加下面所有的即可 父项目pom.xml在标签内添加: <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>2.6.4</version> <executions> <execution> <goals> <goal>repackage</goal> </goals> </execution> </executions> <configuration> <fork>true</fork> <addResources>true</addResources> </configuration> </plugin> </plugins> </build> 子项目pom.xml在标签内添加,注意要在父项目xml里定义版本: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> 更改IDEA设置

python查看时间序列数据的季节规律matplotlib画时间(10分钟为间隔)序列坐标

目录 0 问题描述1. 案例12. 案例2自己尝试参考资料 0 问题描述 将多个时间序列数据,绘制到一张图上,每段时间序列数据一般只有几个月,少则 1 个月左右,想看它们的季节规律,需要去除年份,只看月份。 也就是横轴是1月1日–12月31日,纵轴是要研究的变量。 1. 案例1 from datetime import datetime import matplotlib.dates as mdates import matplotlib.pyplot as plt dates = ['2016010106','2016010107','2016010108','2016010109','2016010110','2016010111','2016010112','2016010113', '2016010114','2016010115','2016010116','2016010117','2016010118'] #把string格式的日期转换成datetime格式 xs = [datetime.strptime(d, '%Y%m%d%H') for d in dates] ys = ['36','29','26','22','29','38','48','55','56','60','55','48','51'] fig = plt.figure() ax = fig.add_subplot(1,1,1) #指定X轴的以日期格式(带小时)显示 ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y%m%d%H')) #X轴的间隔为小时 ax.xaxis.set_major_locator(mdates.HourLocator()) plt.plot(xs, ys) plt.gcf().autofmt_xdate() plt.show() 2. 案例2 使用 date_range 再创建一个 datetime,从 2016-01-01 到 2016-12-31 以每小时为单位,长度为 8761。 t_range=pd.date_range('2016-01-01','2016-12-31',freq='H') t_range DatetimeIndex(['2016-01-01 00:00:00', '2016-01-01 01:00:00', '2016-01-01 02:00:00', '2016-01-01 03:00:00', '2016-01-01 04:00:00', '2016-01-01 05:00:00', '2016-01-01 06:00:00', '2016-01-01 07:00:00', '2016-01-01 08:00:00', '2016-01-01 09:00:00', .

【YOLOv5】 02-标注图片,训练并使用自己的模型

在上一篇文章中,我们完成了YOLOv5的安装和测试。如果想检测自定义目标,就需要用到LabelImg来对图片打标签,本篇文章介绍了LabelImg安装与使用,以及如何训练并使用自己的模型。 一、安装LabelImg 输入如下命令进行安装: pip install labelimg 二、使用LabelImg 输入“labelimg”来打开该软件 软件界面如下: 常用的快捷键有: 点击如下按钮,打开样本所在的文件夹 点击如下按钮来框选目标的范围 框选好后,选择存为YOLO格式(即将标记的信息保存为.txt格式) 点击“Save”来保存标记好后的第一张图(这里是灰色是因为已经保存过了),保存到一个指定的文件夹,之后所有标记好的txt都存储到该文件夹中。 注意:保存的文件名要与原始图片的文件名保持一致。每标记一张图都要记得保存! 点击File-》Change Save Dir ,选择刚才存储txt的那个文件夹 点击“Next Image”来准备标注下一个图片 如果遇到只能框选方形,无法框选矩形的情况,只需按下“ctrl+shift+R”就可以恢复创建矩形box 三、训练模型 首先新建训练集和验证集文件夹,分别命名为“train”和“val” “train”和“val”文件夹都需包含“images”和“labels”文件夹。其中,“images”文件夹用于存放图片,“labels”文件夹用来存放txt 将刚才标注好的约75%的图片和标签分别放入“train”中的“images”和“labels”,用作训练集 注意:图片和标签必需一一对应 将剩下的放入“val”中的“images”和“labels”,用作验证集 创建一个yaml文件 文件内容如下: 修改“train.py”中的一些参数 运行train.py来训练,可以看到训练的结果存储在“runs\train\exp4\weights”中 四、使用模型 如下图,将detect.py中的“--weights”参数替换为刚训练好的pt文件路径,“--source”改为待检测的图片路径 五、继续训练 如果想在上一次训练的基础上继续训练模型,可以更改“train.py”中的“--weights”参数,改为上一次训练的pt文件

OpenCV(12): 傅里叶变换以及高通低通滤波器代码复现

引言: 上一篇博客简单介绍了一下傅里叶变换是什么,这篇博客主要讲傅里叶变换在图像处理中的具体应用,同时也会附上例子和代码实战。 知识引用: 我上一章讲的有些复杂。不了解傅里叶变换的同学,我在此可以简单介绍一下它的概念。 傅里叶变换认为,很多函数,都可以用正余弦函数组合而成。也就是说,所有的函数都能被分解为一系列正余弦函数。而傅里叶变换,主要就是求出这些函数,从而让时域转换为频域。 但是,并非所有函数都能被傅里叶变换表示为正弦和余弦函数的组合,只有满足一定条件的函数才能被傅里叶变换表示。这些条件包括: 函数绝对可积,即在整个实数轴上,函数的绝对值的积分存在;函数平方可积,即在整个实数轴上,函数的平方的积分存在;函数有限长且连续或者具有有限个极值点和有限个间断点且绝对可积。 对于时域,如果我们将一个函数的x轴视为时间,那么这个函数随着自变量的变化而变化,所形成的函数图像就是时域。而频域就是由这个函数分解成的一系列正余弦函数,以这些函数的频率为x轴,振幅为y轴组成的图像就是频域。 这边推荐一下这篇知乎文章,讲的非常好,反正比我好,有兴趣可以看一下。以下图片也转载自这篇文章。傅里叶分析之掐死教程(完整版)更新于2014.06.06 - 知乎 (zhihu.com) 我们换个方向看过去,就能得到它的频域。 以下就是它的频域 频域的x轴指的是频率,y轴代表振幅。那么根据分解出来的正余弦函数的频率有些时候,他们是有限个或者可列无限个,有些时候他们是无限且不可列个,就被分别称为离散傅里叶变换(DFT)和连续型傅里叶变换(CTFT)。上图就是离散型傅里叶变换的频域,连续型自行脑补,它的数据是连续的,不好展示,因为连续型分实部和虚部,实部就是上图转换成连续,虚部就是相位。 基于傅里叶变换的滤波器 对于一张图像,我们可以通过傅里叶变换的原理将其分解为无数个频率的图像。这些图像相互叠加便形成了我们所看到的图像。 那么根据傅里叶变换的原理,我们提出了两种滤波器,高通滤波器以及低通滤波器。 在图像处理中,我们可以将一幅图像看作是一个二维函数,即 f(x,y),其中 x 和 y 是图像中每个像素的水平和垂直位置(可以理解为之前我们说的时域中的x轴,此时的x轴不是时间而是空间坐标),而f(x,y) 表示该位置的亮度值。 而在频域上,我们可以将这个二维函数进行傅里叶变换,得到其频谱 F(u,v)。在频谱中,低频表示的是图像中亮度变化比较缓慢的部分,高频表示的是图像中亮度变化比较剧烈的部分。因此,图像中的低频部分通常包含了图像的整体结构和纹理信息,而高频部分则包含了图像的细节信息和边缘信息。 低通滤波器 低通滤波器的工作原理是保留图像低频的部分,去除高频的部分,会使图像变得模糊。 代码复现: 测试图像为: 第一步:读取灰度图,这里imread方法中传入参数0就是读取灰度图 import numpy as np import cv2 import matplotlib.pyplot as plt #展示图像的方法 def cv_show(title,img): cv2.imshow(title,img) cv2.waitKey(0) cv2.destroyAllWindows() return img = cv2.imread('bird.jpg',0)#读取灰度图 cv_show('img',img)#展示一下图像,按任意键继续 第二步: 将读取的图像数据格式转换为float32.我们都知道opencv读取图像的数据格式是uint8,在使用OpenCV中的cv2.dft()等函数进行傅里叶变换时,需要将输入图像的数据类型转换为浮点型(float)或双精度浮点型(double),以便进行复数类型的运算,获得更准确的频率域表述。 #处理前先把图像的dtype转换成float32,原本是uint8,傅里叶变换得用float32类型才能计算 img_float = np.float32(img) 第三步: #傅里叶变换 dft = cv2.dft(img_float,flags = cv2.DFT_COMPLEX_OUTPUT) dft_shift = np.fft.fftshift(dft) 这段代码的作用是对输入图像img_float进行二维傅里叶变换,并将结果进行中心化处理。

基于java进行点赞功能的实现

1.首先进行建表 大部分点赞都是文章,帖子,或者商品的点赞,然后登录用户进行点赞,创建表的话需要文章,帖子,或者商品的id和用户的id,我这里是文章postId和userId 2.接下来就是代码层面的实现 controller层(PostThumbAddRequest中放的是文章id) @PostMapping("/") public BaseResponse<Integer> doThumb(@RequestBody PostThumbAddRequest postThumbAddRequest, HttpServletRequest request) { if (postThumbAddRequest == null || postThumbAddRequest.getPostId() <= 0) { throw new BusinessException(ErrorCode.PARAMS_ERROR); } // 登录才能点赞 final User loginUser = userService.getLoginUser(request); long postId = postThumbAddRequest.getPostId(); int result = postThumbService.doPostThumb(postId, loginUser); return ResultUtils.success(result); } service层 int doPostThumb(long postId, User loginUser); serviceImpl层(用户串行点赞必须加锁) @Override public int doPostThumb(long postId, User loginUser) { // 判断实体是否存在,根据类别获取实体 Post post = postService.getById(postId); if (post == null) { throw new BusinessException(ErrorCode.

element-ui中input组件的autofocus自动聚焦不生效

element-ui 的 el-input 组件的 autofocus 属性在某些情况下不能实现自动聚焦,有几个可能的原因: 1. autofocus 在移动设备上不被支持。如果是在移动设备上访问,autofocus 不会生效。 2. autofocus 只在页面首次加载时生效。如果通过 vue 路由切换到该页面,autofocus 不会再生效。 3. autofocus 需要在 DOM 渲染完成后生效,如果 DOM 还没有加载完成,则不会生效。 4. modal/dialog 等组件打开时,原页面的 DOM 会被销毁重建,此时 autofocus 也会失效。 要解决这个问题,可以使用 Vue 的 $nextTick 方法,在 DOM 更新后手动触发输入框的 focus 方法: vue <el-input v-model="input" ref="input" /> <script> export default { mounted() { this.$nextTick(() => { this.$refs.input.focus() }) } } </script> 通过这种方式,无论是什么情况,都可以成功触发输入框的聚焦。 所以对于你在模态框中使用 el-input,autofocus 不生效的问题,使用 $nextTick 手动触发 focus 方法是一种很好的解决方案。 希望这能帮助到你! 

从MySQL小表驱动大表说起

刚刚开始学习MySQL的时候,连表查询直接使用left join或者更粗暴点,两个表直接查询,where过滤条件,组装笛卡尔积,最终出现自己想要的结果。 当然,现在left join也是会用的,毕竟嘛,方便! 犹记的当时身为初出茅庐去做的一个面试题,类似这种吧: a表有100条记录,b表有10000条记录,两张表做关联查询时,是将a表放前面效率高,还是b表放前面效率高? 当然,当时虽然不太懂为啥,也没头铁的硬刚,直接是大表在前,小表在后回答,嘿嘿。 不过后来好像绕进了胡同,a*b和b*a有个啥子区别?为啥一定要小表驱动大表? 关于这个,看了不少的文章,其中讲的最深刻,最明了的应该是百度的百家号里面的一篇文章, 由简入深,很能说服人。 当然,后来有时候也会忘了,又在原地打转,今天就小记一下。 首先,连表查询肯定是需要至少把一张表的数据加载到内存的,然后关联查询,比如sql: select u.* from order o left join user u on o.user_id = u.id where u.id = '9527'; 查询的时候,首先将user表的数据加载到MySQL内存,然后去匹配Order表数据。假设user表的数据匹配量是a,Order表的数据匹配量是b,一般来说,on的条件必须是大表的索引,不然,查询速度贼慢,当然小表最好也是索引。还有就是where中的条件,最好也是和on条件的联合索引或者其他主键之类的,这样查询起来会轻松许多。说多了,继续。 那么根据查询的过程,时间复杂度是a*b吗? 当然!不是! 刚开始加载到内存不是还有个操作吗?没错,就是读取User表的操作,也就是a次操作! 所以:小表驱动大表的操作次数就是 a+a*b 那大表驱动小表的操作次数也就很容易得到为:b+b*a 都说了,b是大表,那么b >a,自然(b+b*a) >(a+a*b) 仅仅看扫描的次数,也能看到,小表驱动大表方案更优! 然后,仅仅是如此? 当然不! 先说内存方面,将数据加载的内存,然后进行对比,获取到最终的结果,如果大表驱动小表,需要将大表数据加载到内存,无疑,这必然占据大量的系统内存,要知道内存的每一分空间都是珍贵的,内存占用过大,必然会挤压其他线程可以使用的空间。而且如果表数据过大,内存放不下,还必须建立临时表,然后一部分一部分的取数据进行对比,那不用说,更慢! 再说,数据IO,将表数据加载到系统内存,肯定要消耗系统IO的。如果是小表驱动大表,也就是需要加载a条数据,然后去匹配过滤数据。反过来,就需要加载b条数据,虽然对比数据的时候都是 a*b次,但是明显加载小表更省IO。 然后,看下数据锁定,可以减少锁竞争的可能,当使用小表驱动大表时,可以避免大表上的锁竞争,因为这些锁会在更早的阶段被获取并且释放。而如果是直接访问大表,则需要在整个查询过程中保持锁定状态,这可能导致其他事务无法正常执行。 为防忘记,小记一下~ 如有错误,还望斧正 no sacrifice,no victory~ 

MySQL主从搭建及主从不同步问题处理

1、使用主从同步的好处: 1.通过增加从服务器来提高数据库的性能,在主服务器上执行写入和更新,在从服务器上向外提供读功能,可以动态地调整从服务器的数量,从而调整整个数据库的性能。2.提高数据安全-因为数据已复制到从服务器,从服务器可以终止复制进程,所以,可以在从服务器上备份而不破坏主服务器相应数据3.在主服务器上生成实时数据,而在从服务器上分析这些数据,从而提高主服务器的性能 2、主从同步机制 1、slave 服务器执行 start slave,开启主从复制开关, slave 服务器的 IO 线程请求从 master 服务器读取 binlog(如果该线程追赶上了主库,会进入睡眠状态)。2、master 服务器的更新SQL(update、insert、delete)被写到binlog, 主库的 binlog dump thread,把 bin log 的内容发送到从库。3、从库启动之后,创建一个 I/O 线程,读取主库传过来的 bin log 内容并写到 relay log(会记录位置信息,以便下次继续读取)。4、slave 服务器的 SQL 线程会实时检测 relay log 中新增的日志内容,把 relay log解析成 SQL 语句,并执行。 3、MySql数据库安装 先检查系统是否装有mysql:rpm -qa | grep mysql (无返回则没有安装) 删除可用:yum remove mysql 下载地址:MySQL :: Download MySQL Community Server 解压:tar -xvf /usr/local/mysql-8.0.30-linux-glibc2.12-x86_64.tar.xz -C /usr/local/ 下载mysql的repo源: wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 安装mysql.rpm包 :rpm -ivh mysql-community-release-el7-5.noarch.rpm 安装rpm包后在 /etc/yum.repos.d 会获取两个yum repo源

链表基本函数操作(带头结点的单链表)

#include <stdio.h> #include<stdlib.h> #include<malloc.h> typedef struct LNode{ int val; struct LNode *next; int length; //链表长度 }LNode,*LinkList; void print(LinkList h); LNode * GetElem(LinkList L,int i); LinkList List_HeadInsert(LinkList &L ); LinkList reverse_node_1(LinkList L); LNode *get_k_node(LinkList L,int k); LNode * removeDupicateNodes(struct LNode * head); LNode * reverse_node( LNode* headtest); int data[6]={1, 2,3,4,5,6}; int main(){//[1, 2, 3, 3, 2, 1] LinkList L; LNode *q; LNode *t; int x; L=List_HeadInsert(L); print (L); printf("\n"); t=reverse_node(L); print (t); return 0; } LinkList List_HeadInsert(LinkList &L ){ LNode *s; int x,i=0; L=(LinkList)malloc(sizeof(LNode));//建立头结点 LNode*r =L; while(i<=5){ //输入9999表示输入结束 s=(LinkList)malloc(sizeof(LNode));//建立要插入的结点 s->val=data[i]; //输入结点值 r->next = s; //尾插法 r=s; //尾插法 i++; } r->next=NULL;//尾插法 L->length=i+1; return L; } void print(LinkList h){//打印带头结点的单链表 LinkList p=h->next; while(p!

C++引用篇

文章目录 一、引用概念及示例二、引用做函数参数二、引用做函数的返回值四、常引用五、引用和指针的区别 一、引用概念及示例 c语言指针存变量地址,然后通过解引用可以访问或者改变变量,且也可以改变指针变量里面存的地址 修改变量这样还需要对指针变量解引用,这样较为麻烦,且修改地址还有些不安全,所以c++中有了同样能修改变量且可以访问变量的名词 这被成为引用引用 引用:引用不是新定义的变量,而是给已存在的变量取一个别名, 不过编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间 引用操作符&它这与取地址操作符一样,不过引用在使用时引用是双目,&左边数据类型,右边为引用变量名, 而取地址操作符是单目操作符,右边为取地址变量名 引用就相当于给别人起外号,虽然一个人可能有很多外号,但是这些外号对应的还是那个人 而对其中一个外号进行改动,其它外号都是在变化的 如有一个人叫张三,别人又叫他法外狂徒,如今我们将法外狂徒判刑十年,是不是张三被判刑了10年 虽然一个变量可能有不同的别名但是这些别名它的空间都为同一个空间,其中一个别名改变 也会影响到其它的别名甚至他本身。 #include<iostream> //在引用时要初始化,要说明是谁的引用 using namespace std; int main() { int a = 0; int& b = a;//对a起别名 int& c = b;//对b起别名 c++;//b的别名改变 cout << a << endl; cout << b << endl; cout << c << endl; b++;//a的别名改变 cout << a << endl; cout << b << endl; cout << c << endl; //b是a的引用,c是b的引用,它们和它所引用的对象共用同一块空间,所以它们地址都相同 cout << &a << endl; cout << &b << endl; cout << &c << endl; return 0; } 二、引用做函数参数 引用作为函数参数的形参,在函数调用时,相当于形参是对实参的引用,所以在函数内部对实参的操作也就是对实参的操作。引用做参数,形参和实参共同有一块内存空间,没有为形参开辟新的内存空间,减少了调用时因为形参开辟内存的损耗,提高了效率

解决node每次修改内容都需要关闭并重启服务器问题

node项目每次修改页面内容都需要 Ctrl+C 终止当前服务,再重新启动 针对此问题,我们可以安装nodemon来解决 // 首先全局安装nodemon npm i -g nodemon 安装完nodemon之后,用 nodemon node文件 命令来启动,就能实现页面修改并保存后服务器自动刷新

【详解C++中的引用】

文章目录 一、什么是引用二、引用规则三、引用特性四、使用场景1.做函数参数2.做返回值五、常引用 ps:为什么类型转换会产生临时变量? 六、引用和指针的区别总结 一、什么是引用 引用就是给一个变量取别名。 注意:这个引用不会新开辟一块空间,而是和原来的变量公用一块空间。 举个例子:李逵,在家称为"铁牛",江湖上人称"黑旋风"。 二、引用规则 引用规则:引用实体类型+&+引用别名 = 引用实体。 比如下面: int main() { int a = 10; //引用 int& ba = a; ba = 20; printf("%d ", a); return 0; } 上面代码为例: 引用对象类型是int + & + 引用别名(ba) = 引用对象(a) C++中的 “&”符号跟类型在一起是不在是取地址,而是”引用“。 现在ba这个就是a的别名,和a是同一块内存空间,改变了ba的内容,就等于改变了a的内容。 同时,一个变量可以有多个引用。 相当于一个人可以有多个别名一样。 就像是:假如你在家被叫做小红,在外面被叫燕燕。你的妈妈叫小红吃饭,然后小红去吃饭了,那燕燕是不是也吃了,你是不是也吃了呢? 三、引用特性 1.引用类型必须是和引用实体是同一类型。 比如: 报错的原因是:引用对象的类型和引用实体的类型不一致。 引用的对象a是int类型,而给它取别名却是double类型,这是不允许的。 2.引用在定义时必须初始化 比如: 这也是不允许的。 3. 引用一旦引用一个实体,就不能引用其他实体。 比如: int main() { int a = 10; //引用 int& pa = a; int x = 20; pa = x; return 0; } 这段代码,有错误吗?

vue3新特性 v-bind

v-bind 单文件组件的 <style> 标签支持使用 v-bind CSS 函数将 CSS 的值链接到动态的组件状态 <script setup lang="ts"> const homeWith='100px' const theme={ color:'red' } </script> <template> <div class="home"> </div> </template> <style scoped lang="scss"> .home{ width: v-bind(homeWith); height: 100px; background-color: v-bind('theme.color'); } </style>

知识蒸馏(Knowledge distillation)必读论文合集

1.早期论文 Model Compression, KDD 2006 Do Deep Nets Really Need to be Deep?, NIPS 2014 Distilling the Knowledge in a Neural Network, NIPS-workshop 2014 2.特征蒸馏(Feature Distillation) FitNets: Hints for Thin Deep Nets, ICLR 2015 Paying More Attention to Attention: Improving the Performance of Convolutional Neural Networks via Attention Transfer, ICLR 2017 https://github.com/szagoruyko/attention-transfer Learning Deep Representations with Probabilistic Knowledge Transfer, ECCV 2018 https://github.com/passalis/probabilistic_kt Knowledge Distillation via Instance Relationship Graph, CVPR 2019

Ubuntu20.04+Windows10双系统迁移新硬盘并解决引导损坏全流程总结

目录 一. 备份原有系统1.1 压缩原系统的/目录 二. 安装新系统三. 迁移系统四. 引导修复4.1 Ubuntu引导修复4.2 Win10引导修复4.3 双系统grub修复 因工作需要,欲将Ubuntu系统迁移到一块全新SSD中,此文章提供了系统迁移后所产生一系列问题的解决方案。 原有软硬件环境: OS1:Ubuntu20.04 (nvme0, PM981 512GB) OS2:Windows10 (nvme1, SN850X 1TB) 现有全新SSD 致态7100Plus 2TB一块,任务为将PM981替换掉,并将Ubuntu系统和原有环境原封不动迁移到2TB的新硬盘中。 一. 备份原有系统 1.1 压缩原系统的/目录 sudo tar -cvpzf ubuntu_backup.tar.gz --exclude=/proc --exclude=/tmp --exclude=/home --exclude=/boot --exclude=/lost+found --exclude=/media --exclude=/mnt --exclude=/run / 这里排除了几个不需要的文件夹: proc 存放系统的进程文件, 根据当前系统中运行的进程动态改变 tmp 存放系统缓存文件 home 因为home目录单独挂载在一个分区, 所以待会单独打包 root 因为root目录单独挂载在一个分区, 所以待会单独打包 lost+found 系统发生异常时尝试根据此文件夹中的内容进行恢复 media 插入外部存储设备如u盘时系统自动挂载的位置 mnt 提供给用户手动挂载设备的文件夹 run 系统运行时产生的日志文件 二. 安装新系统 首先使用u盘制作一个ubuntu的安装盘,制作安装盘的软件可以选择ubuntu自带的启动盘创建器软件,或者 ultraISO, rufus 之类。启动电脑进入bios设置优先启动设置为 usb 设备, 然后进入安装盘系统,分区根据硬盘大小来设定,如2TB的SSD:

9. docker的使用,docker管理,容器通信,bridge模式详解,pod是什么?和node之间的关系?

如何使用dockerfile创建和构建自定义镜像? 使用dockerfile创建和构建自定义镜像的步骤如下: 编写一个包含构建镜像所需指令的文本文件,命名为dockerfile。在dockerfile所在的目录下,运行docker build -t <image_name> .命令,其中<image_name>是你想要给镜像起的名字,.表示当前目录。等待docker根据dockerfile中的指令逐步执行,并在每一步生成一个新的层。如果构建成功,你可以运行docker images命令查看你的自定义镜像。 例如,如果你想要创建一个基于alpine Linux的镜像,并安装vim和curl软件包,你可以编写如下的dockerfile: FROM alpine RUN apk update RUN apk add vim RUN apk add curl 然后在该文件所在的目录下运行docker build -t alpine .命令,就可以创建一个名为alpine的自定义镜像了。 dockerfile的语法 dockerfile的语法是指用来构建镜像的文本文件中的指令和格式。dockerfile的语法有以下特点: dockerfile必须以FROM指令开头,指定基础镜像。dockerfile中的每一条指令都会创建一个新的镜像层,并对其进行修改。dockerfile中的指令不区分大小写,但是习惯上使用大写来区分参数。dockerfile中可以使用#作为注释,除非#是一个有效的解析器指令。dockerfile中可以使用\作为换行符,以便将一条长指令分成多行。dockerfile中可以使用[]或""来表示参数列表,例如CMD [“echo”, “hello”]。dockerfile中可以使用–chown选项来改变复制到容器内文件的所有者和组。dockerfile中可以使用ARG和ENV来设置变量,ARG在构建时生效,ENV在运行时生效。dockerfile中可以使用RUN, CMD, ENTRYPOINT来执行命令,RUN在构建时执行,CMD和ENTRYPOINT在运行时执行,CMD可以被docker run覆盖,ENTRYPOINT不可以。 容器之间为什么要通信 容器之间为什么要通信,是因为容器是一种轻量级的虚拟化技术,它可以将应用程序和其依赖环境封装在一个隔离的运行单元中。容器之间通信,可以实现应用程序的分布式部署、负载均衡、服务发现、数据共享等功能,提高应用程序的性能、可扩展性和可靠性。 容器之间通信的方式有多种,主要取决于容器是否在同一台宿主机上,以及容器是否需要与外部网络交互。根据搜索结果,常见的容器之间通信的方式有: 在同一台宿主机上,容器之间可以通过共享卷、进程间通信(IPC)或网络命名空间(none, host, bridge, macvlan等)来通信。在不同的宿主机上,容器之间可以通过覆盖网络(overlay)、第三方网络插件(flannel, weave, calico等)或服务网格(istio, linkerd等)来通信。与外部网络交互时,容器之间可以通过端口映射、网络地址转换(NAT)、负载均衡器或域名系统(DNS)来通信。 不同的通信方式有各自的优缺点,需要根据具体的应用场景和需求来选择合适的方案。 一些容器之间通信的示例? 以下是一些使用docker命令或docker-compose文件创建和测试容器之间通信的示例: 使用共享卷来通信:假设你有一个名为producer的容器,它会将一些数据写入到一个名为data的共享卷中,然后你有另一个名为consumer的容器,它会从共享卷中读取数据。你可以使用以下命令来创建和运行这两个容器: #创建一个名为data的共享卷 docker volume create data #创建并运行一个名为producer的容器,它会每秒向共享卷中的data.txt文件写入一行数据 docker run -d --name producer -v data:/data busybox sh -c 'while true; do date >> /data/data.

探秘Linux特殊设备文件:(/dev/null,/dev/zero,/dev/random,/dev/urandom等)

目录标题 第一章:设备文件简介(Introduction to Device Files) 1.1 设备文件概述(Overview of Device Files)1.2 设备文件类型(Types of Device Files)1.2.1 字符设备文件(Character Device Files)1.2.2 块设备文件(Block Device Files) 第二章:/dev/null - 数据黑洞(/dev/null - The Data Black Hole)2.1 /dev/null 的用途(Usage of /dev/null)2.2 /dev/null 的实现原理(Underlying Principles of /dev/null) 第三章:/dev/zero - 数据源泉(/dev/zero - The Data Source) 3.1 /dev/zero 的用途(Usage of /dev/zero)3.2 /dev/zero 的实现原理(Underlying Principles of /dev/zero) 第四章:/dev/random 和 /dev/urandom - 随机数发生器(/dev/random and /dev/urandom - Random Number Generators) 4.1 /dev/random 和 /dev/urandom 的区别(Differences between /dev/random and /dev/urandom) 4.

EF(EFCore)性能优化与高级用法

1、使用AsNoTracking() 使用AsNoTracking()后,将不监听对象的状态(是否被改变);当确定查询出来的数据不会改变的时候使用AsNoTracking(); 使用context.Entry<User>(user).State 查看对象监听状态。 关闭所有监听:context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; 开启所有监听:context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.TrackAll; 2、正确使用Find(id=10)来代替FirstOrDefault(t=>t.id=10) Find会优先查询缓存,当前面已经查询过这条数据的时候使用,而FirstOrDefault每次都会查询数据库;当id=10的数据被修改之后,find查出的数据是新数据。 3、正确区分IQueryable和IEnumerable 3.1 IEnumerable(linq to object)用于操作内存对象。是个迭代器的实现。 3.1.1 Where(t=>t.id>10)中的“t=>t.id>10”是个委托 3.1.2 封装的函数的时候将返回值设为IEnumerable<T>,即使返回return IQueryable<T>也会立刻查询数据库 3.2 IQueryable(linq to sql)用于操作数据库,且继承了IEnumerable。 IQueryable中实现了表达式目录树(Expression),IQueryProvider根据表达式目录树来构建sql语句。 3.2.1 Where(t=>t.id>10)中的“t=>t.id>10”是个表达式目录树 3.2.2 AsEnumerable() 和 AsQueryable()如果后面不继续跟过滤条件等,效果是一样的。 如果后面加了Where / Select / Take() /Skip 等条件,AsEnumerable()先查数据库再过滤,AsQueryable()将条件生成sql,一起在数据库中过滤。 4、正确使用导航属性 和 延迟查询(延迟加载) 在主表对象中包含一个子表集合对象的属性就是导航属性。跟数据库中的主外键设置无关。 利用延迟加载可以叠加多次查询条件,一次性提交给数据库。 使用建议:在开发中不确定后面是否需要关联表数据,可以使用延迟加载来按需获取数据。 4.1 导航属性要延迟加载必须具备两个条件: a、导航属性是virtual的; b、延迟查询必须是开启的。 EF:context.Configuration.LazyLoadingEnabled=true; (默认就是true的) EF Core: protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (!optionsBuilder.IsConfigured) var builder = optionsBuilder.UseSqlServer(_connStr); optionsBuilder.UseLazyLoadingProxies(); //启用延迟加载 } 4.

k8s1.26安装(kubeadm containerd)

环境背景: k8s-1、k8s-2、k8s3三台主机,1台master节点 ,2台node节点 准备环境 修改主机名(3台分别修改主机名) hostnamectl set-hostname k8s-1 hostnamectl set-hostname k8s-2 hostnamectl set-hostname k8s-3 防火墙关闭 systemctl stop firewalld systemctl disable firewalld 关闭selinux setenforce 0 # 临时关闭 sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config # 永久关闭 关闭swap swapoff -a # 临时关闭;关闭swap主要是为了性能考虑 sed -ri 's/.*swap.*/#&/' /etc/fstab free # 可以通过这个命令查看swap是否关闭了 添加主机名与IP对应的关系 vim /etc/hosts 192.168.2.250 k8s-1 192.168.2.251 k8s-2 192.168.2.251 k8s-3 时间同步 timedatectl set-timezone Asia/Shanghai yum install ntpdate -y ntpdate time.windows.com 将桥接的IPv4流量传递到iptables的链 cat > /etc/sysctl.d/k8s.conf << EOF net.

基于DeepSpeed训练ChatGPT

基于DeepSpeed训练ChatGPT 最少只需一张32G GPU,自己也可以训练一个ChatGPT! 最近微软发布了一个基于DeepSpeed的训练优化框架来完成ChatGPT类模型的训练,博主对其进行了研究并通过此博文分享相关技术细节。 一、配置预览 1、开源仓库:DeepSpeed-Chat 2、配置要求: ● cuda:11.0以上 ● torch:1.12.1+cu113 ● deepspeed:0.9.0 ● transformers:4.29.0.dev0 3、开源语料(Hugging face Dataset): ● Dahoas/rm-static ● Dahoas/full-hh-rlhf ● Dahoas/synthetic-instruct-gptj-pairwise ● yitingxie/rlhf-reward-datasets ● openai/webgpt_comparisons ● stanfordnlp/SHP 4、数据格式样例: 需要包含三个字段,分别为: ● prompt:instruction-prompt,当前的输入; ● chosen:人来反馈选中的回复,或当前pair得分最高的回复; ● rejected:人类反馈未选中的回复,或当前pair得分最低的回复; 个人也可以按照这个格式设计自己的训练数据。 5、数据处理函数(样例): 针对训练数据,可以设计如下几个数据处理函数。 # The prompt should be in the format of: " Human: " + actual_prompt_sentence + " Assistant:" # 只获取prompt字段的数据 def get_prompt(self, sample): return " Human: " + sample['prompt'] + "

OpenCV 图像处理学习手册:6~7

原文:Learning Image Processing with OpenCV 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自【ApacheCN 计算机视觉 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。 当别人说你没有底线的时候,你最好真的没有;当别人说你做过某些事的时候,你也最好真的做过。 六、计算摄影 计算摄影是指使您能够扩展数字摄影的典型功能的技术。 这可能包括硬件附加组件或修改,但主要指基于软件的技术。 这些技术可能会产生“传统”数码相机无法获得的输出图像。 本章介绍了 OpenCV 中用于计算摄影的一些鲜为人知的技术:高动态范围成像,无缝克隆,脱色和非照片级渲染。 这三个位于库的photo模块中。 注意,在前面的章节中已经考虑了该模块内部的其他技术(修复和去噪)。 高动态范围图像 我们处理的典型图像每像素有 8 位(BPP)。 彩色图像还使用 8 位表示每个通道的值,即红色,绿色和蓝色。 这意味着仅使用 256 个不同的强度值。 在数字成像的整个历史中,这个 8 BPP 的限制一直盛行。 但是,很明显,自然界中的光并不只有 256 个不同的水平。 因此,我们应该考虑这种离散化是理想的还是足够的。 例如,已知人眼可以捕获更高的动态范围(最暗和最亮之间的亮度级别数),估计在 1 亿到 1 亿个亮度级别之间。 在只有 256 个光照级别的情况下,有些情况下明亮的光线看起来过度曝光或饱和,而黑暗的场景只是被捕获为黑色。 有些相机可以捕获超过 8 BPP 的图像。 但是,创建高动态范围图像的最常见方法是使用 8 BPP 相机并拍摄具有不同曝光值的图像。 当我们这样做时,动态范围有限的问题显而易见。 例如,考虑下图: 用六个不同的曝光值拍摄的场景 注意 左上方的图像大部分为黑色,但窗口详细信息可见。 相反,右下角的图像显示了房间的细节,但窗口的细节几乎看不见。 我们可以使用现代智能手机相机以不同的曝光水平拍摄照片。 例如,对于 iPhone 和 iPad,从 iOS 8 开始,使用本机相机应用更改曝光非常容易。 触摸屏幕,将出现一个黄色框,侧面带有一个小太阳。 向上或向下滑动可以更改曝光(请参见以下屏幕截图)。

Numpy 数组的合并

将不同的数据源进行合并是数据科学中最有趣的事情之一,这即包括将两个不同的数据集非常简单的拼接在一起,也包括用数据库那样的连接(join)与合并(merge)操作处理有重叠字段的数据集。Series与DataFrame都具备这类操作,Pandas的函数与方法让数据合并变得快速简单。 合并Seies 与 DataFrame 与合并Numpy数组基本相同,numpy是用np.concatenate函数将两个或两个以上的数组合并成一个数组。 import numpy as np import pandas as pd def make_df(cols, ind): """ 一个简单的DataFrame """ data = {c : [str(c) + str(i) for i in ind] for c in cols} return pd.DataFrame(data, ind) # DataFrame 示例 make_df('ABC', range(3)) # 两个或两个以上的数组用numpy的函数合并成一个数组 x = [1, 2, 3] y = [4, 5, 6] z = [7, 8, 9] np.concatenate([x, y, z]) #按照坐标轴合并数组列表或元组,第一个参数是需要合并的数组,axis是设置坐标轴 h = [[1, 2], [3, 4]] np.

一、eNSP模拟器命令行基础操作

文章目录 一、命令行基础1、由用户模式进入[ ]:system-view2、退出当前模式:quit3、设备改名:sysname R14、关闭信息中心,防止弹出日志:undo5、快捷方式6、 查看当前正在执行的所有配置:display current-configuration(dis cu)7、保存配置:save8、查看硬盘:dir 二、基本指令1、显示接口摘要信息:dis ip interface brief2、配置ip地址:int e0/0/0 进入接口e0/0/0,ip add 192.168.1.1 243、查看系统内存以及硬盘:dis version4、查看硬盘:dir5、查看内存:dis memory-usage6、查看cpu:dis cpu-usage 三、文件系统基础 提示:以下是本篇文章正文内容,下面案例可供参考 一、命令行基础 1、由用户模式进入[ ]:system-view 2、退出当前模式:quit 3、设备改名:sysname R1 4、关闭信息中心,防止弹出日志:undo 5、快捷方式 (1)? 命令支持帮助 (2)tab键 支持补全 (3)遇到----More---- :回车键翻一行 空格键翻一页 其他任意键中断显示 (4)reboot 系统重启 (5)ctrl + z 直接回退到用户模式 (6)clear configuration int gi 0/0/1:清除指定接口下的所有命令 6、 查看当前正在执行的所有配置:display current-configuration(dis cu) 注意:display 在任何模式都可执行 7、保存配置:save 8、查看硬盘:dir 二、基本指令 1、显示接口摘要信息:dis ip interface brief 2、配置ip地址:int e0/0/0 进入接口e0/0/0,ip add 192.168.1.1 24 3、查看系统内存以及硬盘:dis version 4、查看硬盘:dir 5、查看内存:dis memory-usage 6、查看cpu:dis cpu-usage 三、文件系统基础 (1)复制:copy vrpcfg.

总结Ansible中常用模块

文章目录 一、ansible实现管理的方式二、Ad-Hoc执行方式中如何获得帮助三、ansible命令运行方式及常用参数四、ansible的基本颜色代表信息五、ansible中的常用模块1.command:远程主机执行命令2.shell:command模块的升级版3.script:执行脚本4.copy:文件管理5.fetch:文件管理6.file:文件管理7.unarchive:解压8.archive:打包9.hostname:管理主机名称10.cron:计划任务11.yum_repository:仓库12.dnf:管理软件13.service:管理系统服务状态14.firewalld:火墙管理15.user:管理远程主机上的用户16.group:管理远程主机上的组17.lineinfile:替换18.playbook19.replace:替换20.setup:采集信息21.debug:显示信息echo 六、其他模块的用法:ansible-doc 命令 一、ansible实现管理的方式 Ad-Hoc ##利用ansible命令直接完成管理,主要用于临时命令使用场景 playbook ##ansible脚本,主要用于大型项目场景,需要前期的规划 二、Ad-Hoc执行方式中如何获得帮助 ansible-doc ##显示模块帮助的指令 #格式 ansible-doc [参数] [模块...] #常用参数 -l ##列出可用模块 -s ##显示指定模块的playbook片段 三、ansible命令运行方式及常用参数 #格式: ansible 清单 -m 模块 -a 模块参数 #常用参数 #--version ##显示版本 #-m module ##指定模块,默认为command模块 #-v ##详细过程 -vv -vvv更详细过程 #--list ##显示主机列表,也可以用--list-hosts #-k ##提示输入ssh连接密码,默认key认证 #-C ##预执行检测 #-T ##执行命令的超时时间,默认10s #-u ##指定远程执行的用户 #-b ##执行sudo切换身份操作 #--become-user=USERNAME ##指定sudo的用户 #-K ##提示输入sudo密码 四、ansible的基本颜色代表信息 绿色 ##执行成功但为对远程主机做任何改变 黄色 ##执行成功并对远程主机做改变 红色 ##执行失败 五、ansible中的常用模块 1.command:远程主机执行命令 #功能: 在远程主机执行命令,此模块为默认模块 #常用参数 chdir ##执行命令前先进入到指定目录 cmd ##运行命令指定 creates ##如果文件存在将不运行 removes ##如果文件存在将运行 free_form ##在远程主机中执行的命令,此参数不需要加 #实例 ansible all -m command -a "

PHP+xshell线上同步

一.xshell连接腾讯云 二.打开php 工具->Deployment->Connection 三.修改配置(域名 目录) 四.新建文件并编辑保存 五.同步并上传到xshell 六.在xshell找到该文件 七.查看该文件(同步成功) 八.从xshell中同步到php (编辑xshell中文件并保存) 九.PHP找到工具->Deployment->Download from 十.同步成功

Docker下运行多个ClickHouse容器,在ReplicatedMergeTree引擎中借助Zookeeper同步数据时日志提示“DNS_ERROR”且数据同步失败的解决方案

前置准备 目的 在物理机中基于Docker服务运行两个Clickhouse容器,配置并连接Zookeeper服务器;依照官网对ReplicatedMergeTree引擎的描述分别在两个容器中创建副本表;通过Zookeeper对ClickHouse的支持达到数据同步,最终让两台ClickHouse互为数据副本(Data Replication). 准备 物理机基础环境 IP地址:192.168.182.10 Docker容器和IP信息 服务名称网段名称IP地址主机名Docker执行命令CK节点1(第一个ClickHouse容器)bridge172.17.0.37409ace09488docker run -d --name clickhouse-server-c1 --ulimit nofile=262144:262144 --volume=/software/docker/clickhouse/ck1/config:/etc/clickhouse-server/ -v /software/docker/clickhouse/ck1/data:/var/lib/clickhouse -p 8123:8123 -p 9000:9000 -p 9009:9009 yandex/clickhouse-serverCK节点2(第二个ClickHouse容器)bridge172.17.0.4b22679b9d346docker run -d --name clickhouse-server-c2 --ulimit nofile=262144:262144 --volume=/software/docker/clickhouse/ck2/config:/etc/clickhouse-server/ -v /software/docker/clickhouse/ck2/data:/var/lib/clickhouse -p 8124:8123 -p 9001:9000 -p 9010:9009 yandex/clickhouse-serverzookeeperbridge172.17.0.5不重要docker run --name zookeeper -d -p 2181:2181 zookeeper ClickHouse服务配置 3.1. CK节点1和CK节点2的config/config.d目录中新建metrika-share.xml配置文件,并写入以下配置 metrika-share.xml 内容 <?xml version="1.0"?> <clickhouse> <zookeeper> <node> <!--因zookeeper的2181端口已对外暴露,此处可直接使用本机地址访问,防止Zookeeper IP地址变动--> <host>192.168.182.10</host> <port>2181</port> </node> </zookeeper> </clickhouse> 3.2 CK节点1和CK节点2的config.xml配置中搜索<include_from> 标签,添加为以下内容 <!--因Docker挂载目录已映射成功,故此处可以直接连接到下列配置--> <include_from>/etc/clickhouse-server/config.

泛型的用法

为什么用泛型 早期的Object类型可以接收任意的对象类型,但是在实际的使用中,会有类型转换的问题。也就存在这隐患,所以Java提供了泛型来解决这个安全问题。 什么是泛型 ● 泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。 ● 参数化类型,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式,然后在使用/调用时传入具体的类型。 泛型类 泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法. 泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。 一个最普通的泛型类: public class Demo<T>{ / /T可以为任意标识符,常见的如T、E、K、V等形式的参数常用于表示泛型 private T key; / /key这个成员变量的类型为T,T的类型由外部指定 public Generic(T key) { / /泛型构造方法形参key的类型也为T,T的类型由外部指定 this.key = key; } public T getKey(){ / /泛型方法getKey的返回值类型为T,T的类型由外部指定 return key; } } 传入的实参类型需与泛型的类型参数类型相同,即为Integer. Demo<Integer> genericInteger = new Demo<Integer>(123456); 1.泛型的类型参数只能是类类型。 2.泛型的类型参数可以有多个。 3.如果没有定义具体类型,默认为Object。 从泛型类派生子类 子类也是泛型类,子类和父类的泛型类型要一致 class A<T> extends Demo<T> (1)父类是泛型类(没指定类型) 子类继承父类后,也是泛型类,子类定义类型后,父类类型也随之明确 子类不是泛型类,父类要明确泛型的数据类型 class A extends Demo<String> (2)子类继承一个泛型类:如果子类 没有定义泛型,那么父类的类型必须在声明时就要明确下来 泛型接口 泛型接口与泛型类的定义及使用基本相同。 public interface Demo<T> { //定义一个泛型接口

using namespace std 是什么意思——C++命名空间

目录 namespace命名空间局部域和全局域namespace展开命名空间指定命名空间 命名空间的嵌套不同文件中的同名命名空间 using namespace std 是什么意思 我们先看一段C代码: #include <stdio.h> #include <stdlib.h> int rand = 0; int main() { printf("%d", rand); return 0; } 我们直接看可能不会发现问题,但是这段代码是运行不出来的 原因就是rand名与stdlib.h库中的函数命冲突,所以运行不出来 命名冲突的发生有2个原因: 1.跟库中冲突 2.一个项目不同部分由不同人编写,最后合并时发生命名冲突 为了避免自己定义的变量名或函数命与库中的名冲突,于是在C++中引入了命名空间这一概念。 namespace命名空间 局部域和全局域 我们先了解一下 局部域 和 全局域,在同一域中不可以创建2个同名变量,但在同一域中可以创建2个同名变量 下面在局部域和全局域建立2个同名变量 #include <iostream> int a = 1;//全局域 int main() { int a = 0;//局部域 printf("%d\n", a); return 0; } 那么在这里如果要输出a的值,那么输出的是全局域中的值还是局部域中的值呢? 答案是:输出局部域中的a值 所以可以得出一个结论:搜索范围是先局部域再全局域,默认是在局部域中搜索,如果没有局部域,再在全局域中搜索 如果想要输出全局域中的a怎么办呢? 使用::域作用限定符,::a就表示全局域中的a #include <iostream> int a = 1;//全局域 int main() { int a = 0;//局部域 printf("

【Jetpack】DataBinding 架构组件 ④ ( 使用 @BindingAdapter 注解为布局组件绑定自定义逻辑 | 网络图片加载 | 本地图片加载 )

文章目录 一、@BindingAdapter 注解1、注解简介2、使用 @BindingAdapter 注解为布局组件绑定自定义逻辑 二、使用 @BindingAdapter 注解绑定加载网络图片静态方法三、使用 @BindingAdapter 注解绑定加载本地图片静态方法四、使用 @BindingAdapter 注解绑定加载网络图片或本地图片静态方法五、完整代码示例1、build.gradle 构建脚本2、AndroidManifest.xml 清单文件3、DataBinding 布局文件4、BindingAdapter 注解类5、MainActivity 组件6、执行结果 博客源码 : https://download.csdn.net/download/han1202012/87701531 一、@BindingAdapter 注解 BindingAdapter 是 DataBinding 数据绑定技术 的组成部分 ; 1、注解简介 借助 @BindingAdapter 注解 可以 将自定义逻辑 绑定到 DataBinding 布局中 ; 在 DataBinding 布局中 , 不只是机械性的显示内容 或者 拼接内容 , 还需要 进行更复杂的操作 ; 如 : 为 ImageView 组件绑定数据模型 , 传入一个 url 网络图片地址 , 在该组件中显示网络图片 , 如果网络图片加载失败或者为空 , 则加载默认的本地资源 ; 上述操作必须 自定义一段代码逻辑进行实现 , 使用简单的数据绑定无法实现该功能 ;

内核/逻辑处理器/线程/多线程/多CPU/多核CPU

文章目录 1. 逻辑CPU2. 线程数和逻辑CPU个数,内核个数3.线程/进程/多核CPU3.1 线程3.2 多核cpu3.3 进程和线程 1. 逻辑CPU 先查看电脑cpu信息,可以看到,是8个逻辑cpu 2. 线程数和逻辑CPU个数,内核个数 在任务管理器中,看到其实是4个内核,但是逻辑处理器是8个,有多少个逻辑处理器,就说明你的cpu可以同时处理几个线程 线程数=逻辑处理器个数 一个物理CPU可以有1个或者多个物理内核,一个物理内核可以作为1个或者2个逻辑CPU。 操作系统可以使用逻辑CPU来模拟真实CPU。 在没有多核处理器的时候,一个物理CPU只能有一个物理内核, 有了多核技术,一个物理CPU可以有多个物理内核,可以把一个CPU当作多个CPU使用,即逻辑CPU。 没有开启超线程时,逻辑CPU的个数就是总的CPU物理内核数。 开启超线程后,逻辑CPU的个数就是总的CPU物理内核数的两倍。 实际能看到的2个物理CPU: 实现16个逻辑CPU的原理图: 参考: 物理CPU,物理CPU内核,逻辑CPU概念详解或者简书:https://www.jianshu.com/p/6a53819fa89b 3.线程/进程/多核CPU 3.1 线程 from multiprocessing import cpu_count print(cpu_count()) > 8 在python中,使用上述代码可以获取当前系统的逻辑cpu个数,也就是支持并发的线程个数。 3.2 多核cpu 左图:多个物理CPU,CPU通过总线进行通信,效率比较低。右图:多核CPU,不同的核通过L2 cache进行通信,存储和外设通过总线与CPU通信 感谢评论区同学的提醒,这里更新一下CPU三级cache的内容,以下内容摘录自:小林coding-图解系统 CPU 的高速缓存,通常可以分为 L1、L2、L3 这样的三层高速缓存,也称为一级缓存、二级缓存、三级缓存。L1缓存是每个CPU核一个,每个 CPU 核心都有一块属于自己的 L1 高速缓存,指令和数据在 L1 是分开存放的,所以 L1 高速缓存通常分成指令缓存和数据缓存。L2 高速缓存同样每个 CPU 核心都有L3 高速缓存通常是多个 CPU 核心共用的 CPU多个核之间L1和L2 cache是独享的,L3 cache是共享的。 3.3 进程和线程 进程是程序的一次执行过程,是一个动态概念,是程序在执行过程中分配和管理资源的基本单位,线程是CPU调度和分派的基本单位,它可与同属一个进程的其他的线程共享进程所拥有的全部资源。联系:线程是进程的一部分,一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程;根本区别:进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位 所以对于程序员来说,其实更多时候是和线程打交道,一个程序是一整个进程,程序中可以有多个线程,用来并行进行不同的事情。 参考: ✅关于多 CPU、多核和多线程cpu的个数、核心数、线程数进程,线程与多核,多cpu之间的关系cpu的核数和进程_CPU与核心及进程和线程认识How many cores does my computer have?

vue中的二次确认用装饰器封装

在 Vue 中编写装饰器可以通过使用 @decorator 的方式,以简洁的方式实现对某个方法的扩展或者功能增强。 下面是一个示例装饰器实现,在调用某个方法之前弹出确认框: import { MessageBox } from 'element-ui'; export function confirmDecorator(propName: string) { return function(target: any, key: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = async function(row: any) { const confirmResult = await MessageBox.confirm(`确定删除${row[propName]}吗?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }); if (confirmResult === 'confirm') { return originalMethod.apply(this, [row]); } }; return descriptor; }; } 在这个实现中,我们将 message 参数添加到了装饰器函数的参数列表中,并在确认对话框消息的拼接中使用了该参数。在使用装饰器时,可以同时指定 message 和 propName 两个参数,例如:

es和redis区别

Redis Redis是现在最热门的key-value数据库。它与MongoDB同在2009年发布,也同样是早期大数据时代的数据库代表作。 Redis的最大特点当然就是key-value存储所带来的简单和高性能了。所谓key-value存储,就是每一条记录只包含一个用于查询数据的Key,以及与之对应的存储数据的value,就如同现实生活中的门牌号与住户,而没有诸如表、字段这些常规数据库中必需有的复杂概念,所有的查询都仅仅依赖于key值。 因此,key-value数据库可谓是数据库中数据结构最简单的一种,也得益于这种简单的结构,再加上Redis会把所有数据加载到内存中的,Redis能得到远高于MongoDB这类常规数据库的读写性能。当然,Redis的功能还不止key-value存储这么简单,相较它的key-value前辈Memcached,Redis还支持数据持久化,list、set等多种数据结构,主从复制备份等一些列功能,因此Redis绝对称得上是key-value数据库中功能最全面、最简单易用的款。 Redis的key-valule存储带来了性能这个优势,但是也给复杂查询带来了很多局限。由于阉割掉了数据表、字段这样的重要特性,且所有的查询都依赖key,因此Redis无法提供常规数据库所具备的多列查询、区段查询等复杂查询功能。 同时,由于Redis需要把数据存在内存中,这也大大限制了Redis可存储的数据量,这也决定了Redis难以用在数据规模很大的应用场景中。 Redis牺牲了常规数据库中的数据表、复杂查询等功能,换来了很大的性能提升,特别适合那些对读写性能要求极高,且数据表结构简单(key-value、list、set之类)、查询条件也同样简单的应用场景。 如果你的数据表结构还挺复杂,你还经常需要做一些复杂查询操作,那你最好还是老老实实用MongoDB或者SQL吧。 ElasticSearch 相较于MongoDB和Redis,晚一年发布的ES可能知名度要低一些,但是ES在搜索引擎领域的名声绝对是是响当当的。相较于其他高大上的数据库产品,ES的出身要屌丝很多。 ES的创建者Shay Banon曾经是一个失业的屌丝程序员,在无事可干的时候为了方便老婆搜索食谱而创建了ES(当然,当时还不叫ES)。不料无心插柳柳成荫,成就了今天最热门的搜索引擎数据库,果然妹子才是程序员工作的最大动力啊! ES也专门成立了自己的Elastic公司已经获得数亿美金融资,当年的屌丝程序员Shay Banon也早已逆袭成为CEO并走上人生巅峰。诸位程序员看官读完这个故事是不是也已经开始内心澎湃的想象自己出任CEO迎娶白富美那一天了? ES的特点,正如其名,那就是搜索。严格的说,ES不是一个数据库,而是一个搜索引擎,ES的方方面面也都是围绕搜索设计的。ES支持全文搜索,这里简单解释下什么是全文搜索:对于“我在北京的一家互联网公司工作”这样的数据,如果你搜索“北京”、“互联网”、“工作”这些关键词都能命中这条数据的话,这就是全文搜索,你每天都在用的百度、Google都属于全文搜索。 值得一提的是,ES的全文搜索对中文也有很好的支持(单是中文分词器就有很多种),绝对能够满足国内大多数人的全文搜索需求。除了搜索之外,ES还会自动的替你对所有字段建立索引,以实现高性能的复杂聚合查询,因此只要是存入ES的数据,无论再复杂的聚合查询也可以得到不错的性能,而且你再也不用为如何建立各种复杂索引而头痛了。 说了这么多ES的优点,你是不是觉得ES简直万能了? 可惜不是的,ES也有很多的短处,最明显的就是字段类型无法修改、写入性能较低和高硬件资源消耗。前边讲到ES会自动的替你建立索引,尽管这能给全文搜索以及聚合查询带来很多好处还能替你省了建索引这一麻烦事,但是这个特性也会带来一堆问题。 ES需要在创建字段前要预先建立Mapping,Mapping中包含每个字段的类型信息,ES需要根据Mapping为字段建立合适的索引。由于这个Mapping的存在,ES中的字段一但建立就不能再修改类型了。 (例如,你建的数据表的某个字段忘了加全文搜索,你想临时加上,但是表已经建好并且已经有很多数据了,这时候该怎么办呢?不好意思,你只能把整个数据表删了再重建一遍!) 因此,ES在数据结构灵活度上高于MySQL但远不如MongoDB。ES的缺点还不止这些,自动建立索引使得ES的写入性能也收到了影响,要明显低于MongoDB。 对于同样的数据ES占用的存储空间也要明显大于MongoDB(建那么多索引能不占空间吗?),对硬件资源的消耗也是非常厉害,大数据量下64G内存+SSD基本是标配,算得上是数据库中的贵族服务了,因此如果你的老板很小气,对于ES的选用可要慎重喽! ES的全文搜索特性使它成为构建搜索引擎的利器。除此之外,ES很好的支持了复杂聚合查询这一特点还使得ES非常适合拿来作数据分析使用。 其实,ES还专门做了与自己配套的ELK套装,给你提供从日志收集到数据可视化分析的一条龙服务,绝对是构建高大上数据分析平台的利器。 但是,ES的高成本和低写入性能这些缺点也注定了它不适合用在那些数据价值不高、对写入性能有要求、数据量大而成本受限的场景中。