前言:在分布式微服务系统中,我们存在这么一种情况,在服务设计之初,进行了分库的设计。例如我们接下来要讲的UPMS用户权限管理服务,在我的设计中,将用户操作日志表和各个业务库分离开了,采用异步消息的方式实现操作日志的记录,这样的设计可以减轻业务库的压力,让操作日志业务(登录、修改密码等日志)的情况无论怎么样都不会影响到主干流程。
Step1:关闭Spring自动装配数据源的操作。 首先,我们还是明确我们的目标:
要操作两个数据库,所以要得到两个数据源。
那么在单个数据源的情况下,SpringBoot会为我们的数据源和连接池进行自动装配,但是此时我们需要建立两个数据源和连接池,Spring就不能为我们自动装配了,所以此时,我们需要关闭Spring的数据源自动装配。
上代码:
上面这段代码,我们在启动SpringBoot时,将DataSourceAutoConfiguration.class自动装配类排除掉,这样Spring就不会再执行自动装配的逻辑了。
Step2:yml配置文件中添加多数据源配置。 我使用的是Nacos配置中心,单数据源配置的代码如下:
单数据源情况下,这里只需要在spring.datasource.druid下直接写配置即可。
接下来我们看一下多数据源该怎么改:
多数据源配置的代码如下:
可以看到,在druid节点下,我们这里配置了两个数据源的子节点配置。
这里我们就完成了我们的配置环节
Step3:代码中配置多数据源并通过注解+AOP的方式实现。(先给出结论,后面有源码解析) 目标:完成共用数据源的抽取,并且在不同的模块中建立多数据源。
Step3-1:创建公共数据源标识。 我们可以在公用的Core模块中的常量类中去定义公用的数据源标识以用于全局数据源的管理。
上代码:
我们在这里启用了一个公共数据源,改数据源标识将会被所有需要使用这个公共数据源的模块所使用。
Step3-2:通过注册表模式的形式存储每个数据源标识。 我们通过一个静态Map去保存各个数据源标识,这可以看作为一个注册表模式(类似策略模式),后面我们会将该注册表中的数据源标识注册进多数据源路由表中去。
注意:这个DataSourceType是跟着业务模块走的,即应写在业务模块中并非Core公用模块中,需要多少个数据源,就往里面加。
Step3-3:创建多数据源路由对象。 数据源标识设置好了,那怎么让Spring能通过我们的标识找到对应的数据库呢?此时我们就需要一个多数据源路由对象,实现Spring提供的AbstractRoutingDataSource抽象类就可以完成我们的数据源选择。
上代码:
我们这里实现了Spring提供的AbstractRoutingDataSource抽象类,并重写了其中的determineCurrentLookupKey方法,而这个方法就是为了筛选我们的数据源的。
我们翻译一下这个方法名:“确定当前查询键”,大概可以猜出这个方法的意思:要把我们的路由查询键返回,而这个路由查询键,就是我们设定的数据库标识。(看到这里可能会有点疑惑,到后面会讲解为什么我们通过路由查询键就能找到对应的数据源对象) Step3-4:基于ThreadLocal线程变量在线程中传递动态路由键。 问:我们怎么将动态路由键传入到多数据源路由对象的determineCurrentLookupKey方法中并返回呢?
答:我们有三种方案:
1、使用全局变量传递路由键,这种方式虽然简单,但是会有并发问题,多个线程间的路由键会互相影响。
2、通过在方法的参数中传输路由键, 这需要改变方法签名和调用方式,可能涉及大范围的代码修改。
3、通过显式的上下文对象来传递路由键,也就是创建一个单独的上下文对象,通过这个上下文对象在函数调用过程中传递路由键。
那么1和2的方法都会产生一些问题,那么我们直接选用第3种通过上下文对象传递,ThreadLocal则是一个非常好的选择,它会创建一个线程独有的副本来存储其中的值。
上代码:
在这里,我们创建了一个上下文传递用的ThreadLocal,里面存储的就是我们指定的数据源路由键,这时,我们就可以在determineCurrentLookupKey方法中通过该ThreadLocal获取到当前线程需要执行的数据源的路由键了,代码如下图。
Step3-5:编写用于指定数据源的注解。 上代码:
这里我们在Core模块中定义一个MyDataSource注解,其中的value属性就是我们需要查找的路由键,而这个路由键的来源就是我们在ApplicationConstant全局常量或DataSourceType中的定义的路由键。
Step3-6:编写切面类,并通过自定义注解完成数据源路由键的传递。 上代码:
这一步,我们定义了数据源动态切面类,在这个切面中,我们的切点是所有被DataSource注解标记的Service方法,拦截后,获取切点上的@MyDataSource注解并读取其中的value(路由键),最后放入ThreadLocal中,并且如果当前线程前面已经设置了另一个数据源,则返回前面的数据源的路由键,当前方法结束时,在finally中将原来的路由键再设置回去,以让上一层代码能够走回正常的数据源。
Step4:配置多数据源并注册到Spring中。 在之前,我们关闭了DataSource的自动配置,所以在多数据源的情况下,我们要对每一个数据源都注册一个数据源Bean,然后注册到Spring的多数据源路由表中去。
上代码:
那么这个配置类里面,就配置了我们系统中的两个数据源,一个是upms数据源(当前模块业务库),另一个是公共模块数据源。
在这个类中,我们不仅注册了两个数据源的Bean,还需要注册一个多数据源路由对象,然后将里面的两个数据源加入到路由表里面去,其中targetDataSources就是我们的数据源Map<Integer, DataSource>,而DefaultTargetDataSource就是我们的默认数据源,当我们没有指定数据源时,Service会使用默认数据源。
Step5:测试代码。 跟着上面的步骤,我们就已经完成了我们的高可用的灵活的多数据源配置。接下来写两个Service分别测试不同的数据源。两个数据源对应的库如下图:
然后创建一个Controller,在里面分别调用两个不同的Service,其中mapCodeService是加了@MyDataSource注解的。如下图所示:
接下来我们使用工具分别调用这两个接口。如下两张图所示:
到这里,我们发现,两个Service都可以获取到数据,那么意味着我们当前模块成功对两个库进行了查询,多数据源配置成功了!
至此,我们已经完成了基于注解+AOP的动态多数据源的配置,其中还涉及到了ThreadLocal等知识,如果有什么错误或不懂的地方,欢迎各位一起讨论。
接下来是源码解析部分,各位有兴趣的也可以看一看。
思考:在多数据源的情况下,Spring是怎么管理我们的数据源的呢?又是怎么做到调用的时候可以动态的选择数据源的呢? 答:通过实现Spring提供的AbstractRoutingDataSource抽象类来完成我们的数据源配置。
上源码:
public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean { @Nullable private Map<Object, Object> targetDataSources; @Nullable private Object defaultTargetDataSource; private boolean lenientFallback = true; private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup(); @Nullable private Map<Object, DataSource> resolvedDataSources; @Nullable private DataSource resolvedDefaultDataSource; public AbstractRoutingDataSource() { } public void setTargetDataSources(Map<Object, Object> targetDataSources) { this.
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
Java异常:Java.util.ConcurrentModificationException异常处理 前言一、迭代器Iterator是什么?二、Java.util.ConcurrentModificationException原因 前言 在开发中使用了迭代器对 List 进行遍历,遇到了java.util.ConcurrentModificationException报错,本文记录了这个错误出现的原因和如何解决
一、迭代器Iterator是什么? 迭代器是属于设计模式之一,迭代器模式提供了一种方法来顺序访问一个聚合对象中各个元素,而不保留该对象的内部表示。
1)Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。 2)所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。 3)Iterator仅用于遍历集合,Iterator本身并不存放对象。 常见使用形式为:
import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class TestDemo { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.add(111); list.add(222); list.add(333); Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()) { int value = iterator.next(); System.out.print(value + " "); } } } 二、Java.util.ConcurrentModificationException原因 一个典型的代码实例:
import java.util.ArrayList; import java.util.Iterator; import java.util.List; @SuppressWarnings({"all"}) public class TestDemo { public static void main(String[] args) { List<Integer> list = new ArrayList<>(); list.
文章目录 简介InfluxDB 的使用场景为什么不用关系型数据库1.X 的 TICK 技术栈与 2.X 的进一步融合influxDB 版本比较与选型 安装部署 InfluxDB下载安装进行初始化配置 理论和原理InfluxDB 行协议常用概念Prometheus 数据格式时序数据库中的数据模型普通关系型数据库中的表InfluxDB 中的数据表示理解序列的概念至关重要双索引设计与高效查询思路我一次只能查询一个序列吗时间线膨胀(高基数问题) 存储引擎LevelDBBoltDBTSM存储引擎 目录与文件结构WAL 文件TSM 文件HeaderBlocksIndex间接索引Footer InfluxDB 入门(借助 Web UI)数据源相关Load Data(加载数据)管理存储桶示例 1:创建 Bucket 并从文件导入数据管理 Telegraf 数据源示例 2:使用 Telegraf 将数据收集到 InfluxDB管理抓取任务示例 3:让 InfluxDB 主动拉取数据管理 API Token 查询工具Data Explorer示例 4:在 Data Explorer 使用查询构造器进行查询和可视化Notebook示例 5:使用 NoteBook 查询和可视化数据 简介 InfluxDB 的使用场景 InfluxDB 是一种时序数据库,时序数据库通常被用在监控场景,比如运维和 IOT(物联网)领域。这类数据库旨在存储时序数据并实时处理它们。
比如。我们可以写一个程序将服务器上 CPU 的使用情况每隔 10 秒钟向 InfluxDB 中写入一条数据。接着,我们写一个查询语句,查询过去 30 秒 CPU 的平均使用情况,然后让这个查询语句也每隔 10 秒钟执行一次。最终,我们配置一条报警规则,如果查询语句的执行结果>xxx,就立刻触发报警。
上述就是一个指标监控的场景,在 IOT 领域中,也有大量的指标需要我们监控。比如, 机械设备的轴承震动频率,农田的湿度温度等等。
文章目录 一、Location1.1 location没有'/'1.2 location有'/' 二、URL自动加'/'三、proxy_pass3.1 不增加目录3.2 增加目录 四、root和alias五、实例 一、Location nginx每个location都是一个匹配目录,nginx的策略是:访问请求来时,会对访问地址进行解析,从上到下逐个匹配,匹配上就执行对应location大括号中的策略,并根据策略对请求作出相应。
依访问地址:http://www.wandouduoduo.com/wddd/index.html为例,nginx配置如下:
location /wddd/ { proxy_connect_timeout 18000; ##修改成半个小时 proxy_send_timeout 18000; proxy_read_timeout 18000; proxy_pass http://127.0.0.1:8080; } 那访问时就会匹配这个location,从而把请求代理转发到本机的8080端口的Tomcat服务中,Tomcat响应后,信息原路返回。
1.1 location没有’/’ 请求就可以模糊匹配以字符串开头的所有字符串
1.2 location有’/’ 只能精确匹配字符本身。
举例: 配置 location /wandou 可以匹配 /wandoudouduo 请求,也可以匹配 /wandou*/duoduo
等等,只要以 wandou 开头的目录都可以匹配到。而 location /wandou/ 必须精确匹配 /wandou/ 这个目录的请求,
不能匹配 /wandouduoduo/ 或 /wandou*/duoduo 等请求。
二、URL自动加’/’ 有时候访问的地址要求后面以 / 结尾,如果用户忘记输入 /,Nginx 就会自动加上 /。
通过一个例子来演示问题:
server { listen 80; server_name localhost; location / { root html; index index.
当数据集存在偏差时,训练出的模型可能会对某些类别或观点表现出倾向性,而忽略其他类别或观点。这种偏差可能会导致不公平的结果或误导性的决策。因此,消除训练数据中的偏差至关重要。
训练数据可能存在多种类型的偏差。以下是一些常见的数据偏差类型:
1. 标签偏差(Label Bias):标签偏差是指训练数据集中的标签或类别分布不均衡的情况。如果某个类别的样本数量远远超过其他类别,模型可能会倾向于预测为该类别,而不论其他类别的情况。标签偏差可能导致模型的判断不公平,给不同的类别带来不平等的对待。
2. 样本选择偏差(Sampling Bias):样本选择偏差是指构建训练数据集时对样本选择的方式引入的偏差。如果样本选择不随机或倾向于某些特定特征,可能会导致训练出的模型在预测时对这些特征有较高的依赖性,而忽略其他特征。
3. 人为偏差(Human Bias):人为偏差是指因数据标注员或采集员的主观偏好或判断引入的偏差。标注员在标注数据时可能存在个人观点、文化偏好或认知偏见,这些偏差可能会传递到训练数据中,影响模型的学习和预测。
4. 数据源偏差(Source Bias):数据源偏差是指训练数据所涵盖的数据源不平衡或有所偏好。如果数据集中的数据主要来自特定地区、特定网站或特定社交媒体平台,可能无法充分代表整体的数据分布,导致模型在处理其他来源的数据时表现不佳。
5. 时效性偏差(Temporal Bias):时效性偏差是指随着时间的推移,训练数据所代表的现象或环境发生变化,而训练出的模型未能及时适应变化。这种偏差可能导致模型在处理新的数据或变化的情况时出现偏差。
6. 隐式偏差(Implicit Bias):隐式偏差是指模型在训练过程中自身学习到的偏好或倾向。模型可能倾向于学习训练数据中常见的模式,而对罕见或极端的模式表现较差。这种偏差可能影响模型在边界情况下的泛化能力。
了解和识别这些数据偏差类型,可以更好地调整训练数据集,以减少偏差对模型性能和结果的影响。同时,消除数据偏差也需要综合运用多种方法和技术,如数据清洗、数据增强、反偏差技术等。
以下是一些可行的方法:
1. 数据多样化:确保训练数据集的多样性,多样化的数据能够减少特定偏差对模型训练的影响,可以通过从不同来源收集数据、合成数据或引入各种视角来实现。
2. 数据清洗和筛选:彻底清洗和筛选训练数据,去除可能引入偏差的错误或不准确数据。精准的数据清洗可以提升训练数据的可靠性和准确性。
3. 平衡数据集:在构建训练数据集时,要确保各类别或观点的样本数目相对平衡。如果某些类别或观点在数据集中占据过大比例,可能会导致训练出的模型偏向这些类别或观点。通过平衡数据集,可以减少特定偏差的影响。
4. 反偏差技术:使用一些反偏差技术可以有效减少训练数据中的特定偏差。例如,可以使用重加权方法来重新调整训练数据样本的权重,以平衡不同类别或观点的影响。另外,误差修正方法也可以用来校正具有偏差的数据样本。
5. 利用数据增强:通过数据增强技术,可以生成额外的训练数据,增加数据的多样性和覆盖范围。数据增强可以包括数据合成、样本生成、样本转换等方法,通过扩充训练数据集来减少偏差对模型训练的影响。
6. 审查模型输出:在使用训练模型进行预测或结果生成时,需要仔细审查模型输出是否表现出任何偏差。如果发现模型输出存在偏差,需要对模型进行调整和修正,例如增加对少数类别或观点的训练样本,或者引入附加的正则化约束。
7. 定期更新模型:定期更新训练模型非常重要,通过不断更新数据和技术来减少偏差的影响。定期审查并重新训练模型可以保持模型的准确性和公平性。
综上所述,当数据集存在偏差时,训练出的模型可能对某些类别或观点表现出倾向性,而忽略其他类别或观点。这种偏差可能会导致不公平的结果或误导性的决策。
了解和识别数据偏差类型,并采取相应的解决方法,是调整训练数据集质量,减少偏差对模型性能影响的关键。只有综合运用多种方法,才能更好地消除训练数据中的偏差,训练出更加公正、准确和可靠的机器学习模型。
Gaussian Noise: Gaussian Noise | Hasty.ai
from matplotlib import pyplot from PIL import Image import numpy as np url=r"C:\Users\jimore\Pictures\girl.jpeg" img=np.random.rand(100,100) # img=np.array(Image.open(url)) print(img) pyplot.figure(1) pyplot.imshow(img) Gaussian_noise=np.random.normal(22,10,img.shape) print(Gaussian_noise) noisy_img=img+Gaussian_noise print(noisy_img) pyplot.figure(2) pyplot.imshow(noisy_img) clean_img=noisy_img-Gaussian_noise pyplot.figure(3) pyplot.imshow(clean_img) pyplot.show() Rayleigh Noise: How To Make Rayleigh Noise On Image - C# Guide - Epoch Abuse
from matplotlib import pyplot from PIL import Image import numpy as np url=r"C:\Users\jimore\Pictures\girl.jpeg" import numpy as np def generate_rayleigh_noise(amplitude, size): "
文章目录 一、为什么存在跨域问题二、什么是跨域三、如何解决跨域3.1 CORS(重要)3.1.1 简单请求和非简单请求3.1.2 跨域主要涉及4个响应头3.1.3 简单请求 CORS 处理过程3.1.4 复杂请求 CORS 处理过程(先发 OPTION 请求)3.1.5 SpringBoot框架实现CORS1. CorsFilter过滤器实现全局配置2. 重写WebMvcConfigurer的addCorsMappings 方法实现全局配置3. @CrossOrigin注解局部配置 3.2 Nginx反向代理(重要) 一、为什么存在跨域问题 浏览器不允许跨域请求是因为跨域请求可能引发安全风险。同源策略(Same-Origin Policy)是一种浏览器安全机制,它要求网页中执行的脚本只能与同一源(协议、域名和端口相同)下的资源进行交互。
同源策略有助于防止恶意网站窃取用户的敏感信息或进行其他安全攻击。如果浏览器允许跨域请求,那么恶意网站就可能通过在用户浏览器中执行脚本来访问其他域名下的敏感数据,例如用户登录凭证、私密文件等。
虽然跨域请求受到同源策略的限制,但浏览器提供了一些机制来支持安全的跨域通信,如跨域资源共享(CORS)和 JSONP(JSON with Padding)等。通过这些机制,服务器可以明确告知浏览器哪些跨域请求是安全可信的,并授权浏览器访问相关资源。
尽管存在跨域请求的限制,但同源策略对于保护用户和维护网络安全至关重要。开发人员可以使用服务器端的代理或通过在服务器上配置 CORS 等方式来解决跨域问题。这样可以确保跨域请求只在受信任的环境下进行,并减少潜在的安全风险。
二、什么是跨域 当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
当前页面url被请求页面url是否跨域原因http://www.test.com/http://www.test.com/index.html否同源(协议、域名、端口号相同)http://www.test.com/https://www.test.com/index.html跨域协议不同(http/https)http://www.test.com/http://www.baidu.com/跨域主域名不同(test/baidu)http://www.test.com/http://blog.test.com/跨域子域名不同(www/blog)http://www.test.com:8080/http://www.test.com:7001/跨域端口号不同(8080/7001) 三、如何解决跨域 3.1 CORS(重要) CORS(Cross-Origin Resource Sharing,跨域资源共享)是一个 W3C 标准,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。
整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。
其实 CORS 很好理解,服务端在 HTTP 响应中添加一个 Header Access-Control-Allow-Origin:http://www.masikkk.com header 值是允许的源,浏览器看到自己的源和服务端返回的能匹配上,就允许跨域。
一、下载docker(官网)(Linux系统centos7)
Install Docker Engine on CentOS | Docker Documentation
二、根据官网的相关步骤:
1.卸载旧的docker, 如果没有下载过可以跳过
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
2.安装相关依赖
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
3.安装最新版的docker
sudo yum install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
4.启动docket服务并设置开机启动
sudo systemctl start docker
systemctl enable docker
5.查看docker服务是否启动成功
ps aux|grep docker
看到有dockerd进程代表启动成功。
三、遇到的问题
1.安装docker时报错:
报错信息:
failure: repodata/repomd.xml from mirrors.aliyun.com_dockece_linux_centos_docker-ce.repor: [Errno 256] No more mirrors to try.
字面意思 无法解析域名
原因无非有三 1、域名本身就挂了
2、自己服务器没网
3、自己服务器没配DNS
解决方案 1和2就不用说了,自己检查一下
像是一些新开的服务器,它并没有配DNS,导致本身虽然有互联网流量但却无法使用curl或ping、或是其他一些指令去访问其他互联网域名
直接加上这个DNS
vi /etc/resolv.conf
把无效的DNS注释掉
加上nameserver 8.8.8.8 或 nameserver 114.114.114.114 即可
我记得在网络配置里也可以,具体文件名叫做 ens-xx
但是这个需要重启网络,不太建议用
小伙伴不知道怎么将网卡链接到VMware虚拟机系统里面,因此今天我们就做一个简单的教程,教大家如何连接虚拟机使用:
1.插上usb网卡,然后如下图所示操作:
2.点击连接网卡到虚拟机之后,查询一下网卡是否识别到,通常都是右击桌面点击打开终端,终端输入ifconfig,出现wlan0,(有的系统比如Ubuntu会显示的是wlan0的全称)就说明网卡已经连接到虚拟机了,就可以开始使用了,如下图所示:
3.如果连接上网卡之后输入ifconfig没有显示wlan0,可以输入ifconfig -a看一下 常见问题:
如果连接虚拟机这里,如下所示没有显示网卡,那么启动usb服务即可:
相关操作如下:
1.首先按下win+r打开运行窗口
在文本框输入services.msc,然后按回车键即可进入服务 2.然后我们在服务里面找到如下图所示项:VMware USB Arbitration Service 右击启动
3.启动了之后,接下来我们打开vm虚拟机,开始连接网卡,如下图所示:,点击链接网卡
文章目录 行业介绍历史背景20世纪60年代 软件作坊70年代 软件危机80年代 软件过程控制90年代 重型过程2001~今 敏捷正在流行 敏捷宣言 敏捷实践一个高效团队的启示敏捷=概念+优秀实践+具体应用理念优秀实践 敏捷核心-迭代开发聚焦客户价值:交付刚刚好的系统 行业介绍 ISO 9000 标准将在原来八大原则的基础上新增敏捷原则
DOD 5000.2 推荐迭代
历史背景 20世纪60年代 软件作坊 70年代 软件危机 80年代 软件过程控制 引入成熟的生产制造管理方法
以“过程为中心”分阶段来控制软件开发(瀑布模型)
90年代 重型过程 开发效率降低、响应速度变慢
2001~今 敏捷正在流行 需求变化快
交付周期成为企业核心竞争力
轻量型 软件开发顺应时代变化,从重型过程转向轻量型敏捷
敏捷宣言 个体和交互 胜过 过程和工具
可以工作的软件 胜过 面面俱到的文档
客户合作 胜过 合同谈判
响应变化 胜过 遵循计划
敏捷宣言是敏捷起源的基础
敏捷实践 一个高效团队的启示 清晰的目标
职责清晰、分工明确
加强团队凝聚力
良好的沟通
积极的工作范围
敏捷=概念+优秀实践+具体应用 理念 优秀实践 站立会议
持续集成
单一主干
系统剖析
重构
结对编程
TDD
FDD
迭代
敏捷包括三个层次
随着人们生活水平的提高和城市化进程的加速,餐饮业的发展越来越迅速。然而,餐饮油烟的排放也对环境和人类健康造成了潜在的威胁。为了有效监管餐饮企业的油烟排放,实现环保与餐饮业共赢,引入餐饮油烟在线监测平台变得至关重要。
油烟在线监测云平台是一种集实时监测、数据采集、云计算和大数据技术于一体的在线监测系统。它可以实时监测厨房油烟的排放情况,并将数据通过云平台进行展示,从而实现实时、远程监控烹饪油烟的排放,为环保工作提供强有力的支持。
以一个实际案例为例,某城市在引入油烟在线监测云平台后,对市区内的餐饮企业进行实时监控。当发现某餐厅的油烟排放量超过标准时,云平台立即发出警报,提醒监管部门采取措施。此外,云平台还为城市的环境质量评估、政策制定等提供了有力支持,为改善空气质量、提升居民生活品质做出了重要贡献。
总结起来,油烟在线监测云平台在保护环境、治理油烟污染方面具有显著优势。它通过实时监测和数据分析,为监管部门和企业提供了更加精准、高效的环保解决方案。随着技术的不断进步和发展,相信油烟在线监测云平台将在未来发挥更大的作用,为建设美丽中国、实现可持续发展做出更多贡献。
使用karel写一个简单的程序 硬件环境 Fanuc 6轴机器人,控制器版本V8.30P:
KAREL语言介绍 FANUC机器人除了可以通过编写TP语言程序进行控制以外,还可以通过编写KAREL语言程序进行控制。
KAREL是一种专门用于机器人系统架构的语言,用户可以在PC上创建KAREL程序,然后将其加载到机器人控制器中执行,以从系统层面激活机器人的原始功能。
与在示教器上创建的TP程序一样,用KAREL语言创建的程序也可以在机器人控制器上执行,不同的是:KAREL程序是用来构建机器人系统的,即实现系统的二次开发,而TP程序只能用于执行机器人运动和应用指令;TP程序可以在示教器上创建、编辑和执行,KAREL程序只能在PC上创建,通过编译转换后才能成为机器人可执行的程序,并且程序加载后不能示教器上编辑和修改。
FANUC机器人的KAREL语言并不是真实的KAREL语言,而是基于PASCAL语言开发出的一种高级编程语言。使用KAREL语言程序可以在机器人控制器中创建示教器显示画面,实现I/O信号的后台逻辑处理(简易PLC功能),示教机器人点位和点位数据运算,数值数据四则运算和高级运算,数据的监控、记录以及输出等功能。
需要添加的功能包 Karel (R642)
KAREL Use Sprt FCTN (J971)
如果是TP 程序调用Karel 程序,不添加 karel 功能包,也可以运行karel 程序。
如果需要设置karel 程序的运行方式,需要加载R642 和 J971 软件包。
需要的设置 在menu->系统–>变量里面设置 $KAREL_ENB =1
创建一个TP调用的karel 程序,并传入string参数 第一步在ROBOGUIDE里面创建karel程序 编写如下图的程序
第二步编译karel程序生成PC程序 点击创建按钮生成PC程序
第三步导入pc程序到机器人 略过
第四步使用TP程序调用PC程序测试效果 注意:测试环境是ROBOGUIDE,实体机器人也测过是可以运行的,创建Cell需要注意虚拟机器人和实体机器人的软件版本需要一样否则导入PC程序时候会提示创建PC程序的版本和控制器版本不一样。
测试前设置
新建一个程序RSR0001 并且调用我们导入的TestTPCALLPC程序,并且同时显示程序编辑界面和user界面
按住shift +FWD 执行程序
16:12:35.164 [main] ERROR org.apache.dubbo.config.deploy.DefaultModuleDeployer - [DUBBO] Model start failed: Dubbo Module[1.1.1] start failed: java.lang.NoSuchMethodError: org.apache.curator.framework.api.CreateBuilder.creatingParentContainersIfNeeded()Lorg/apache/curator/framework/api/ProtectACLCreateModePathAndBytesable;, dubbo version: 3.2.2, current host: 192.168.229.1, error code: 5-14. This may be caused by , go to https://dubbo.apache.org/faq/5/14 to find instructions. java.lang.NoSuchMethodError: org.apache.curator.framework.api.CreateBuilder.creatingParentContainersIfNeeded()Lorg/apache/curator/framework/api/ProtectACLCreateModePathAndBytesable; at org.apache.curator.x.discovery.details.ServiceDiscoveryImpl.internalRegisterService(ServiceDiscoveryImpl.java:222) at org.apache.curator.x.discovery.details.ServiceDiscoveryImpl.registerService(ServiceDiscoveryImpl.java:188) at org.apache.dubbo.registry.zookeeper.ZookeeperServiceDiscovery.doRegister(ZookeeperServiceDiscovery.java:101) at org.apache.dubbo.registry.client.AbstractServiceDiscovery.register(AbstractServiceDiscovery.java:143) at java.util.ArrayList.forEach(ArrayList.java:1259) at org.apache.dubbo.registry.client.metadata.ServiceInstanceMetadataUtils.registerMetadataAndInstance(ServiceInstanceMetadataUtils.java:204) at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.lambda$registerServiceInstance$5(DefaultApplicationDeployer.java:875) at org.apache.dubbo.metrics.event.MetricsEventBus.post(MetricsEventBus.java:80) at org.apache.dubbo.metrics.event.MetricsEventBus.post(MetricsEventBus.java:62) at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.registerServiceInstance(DefaultApplicationDeployer.java:873) at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.prepareApplicationInstance(DefaultApplicationDeployer.java:724) at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.checkState(DefaultApplicationDeployer.java:1034) at org.apache.dubbo.config.deploy.DefaultApplicationDeployer.notifyModuleChanged(DefaultApplicationDeployer.java:1022) at org.apache.dubbo.config.deploy.DefaultModuleDeployer.onModuleStarted(DefaultModuleDeployer.java:307) at org.apache.dubbo.config.deploy.DefaultModuleDeployer.startSync(DefaultModuleDeployer.java:177) at org.
1.下载支持M1的nacos镜像 docker pull zhusaidong/nacos-server-m1:2.0.3 2.启动容器 docker run --env MODE=standalone --name nacos -d -p 8848:8848 -p 9848:9848 -p 9849:9849 zhusaidong/nacos-server-m1:2.0.3 3.浏览器打开nacos控制台 http://127.0.0.1:8848/nacos
业务梳理 某业务可以根据Excel模板的方式新增数据,其导入模板中包含组织机构信息,人员信息。以往的做法是用户在导入时自己填写模板。
1.弊端 大数据模板导入时,用户体验较差;客户输入容易出错,导致导入时易产生数据校验错误。 针对如上弊端,产品提出如下需求
需求 对于已知固定数据,采用数据下拉选择填入的方式填充数据对于具有关联关系的数据,能根据上一列填值确定下一列数据的下拉范围某一列的数据可根据前几列是否已填入值确定该列数据的下拉范围 实现 思路 1.学习Excel如何制作下拉框
2.基于Easyexcel实现Excel下拉框选择数据
实现 1.确定下拉框实现数据结构 import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.List; @Data @Builder @NoArgsConstructor @AllArgsConstructor public class ExcelCascade { /** *下拉选项 */ private List<String> options; /** * 级联模板 */ private String parentColTpl; /** * 当前下拉列索引 */ private Integer curColIndex; /** * 下拉列表首行 */ private Integer firstRow; /** * 下拉列表末行 */ private Integer lastRow; /** * 下拉列表名称 */ private String title; } 2.
WECOM-SDK 是开源的企业微信开放 API 的 Java 实现,是目前开源实现中最完整的Java实现。经过近三年的迭代,目前已经实现了企业微信通讯录管理、上下游、客户管理、微信客服、素材管理、消息推送、企微机器人、身份验证、应用管理、OA办公相关接口,开发人员不需要很高的学习成本就能快速优雅地接入企业微信。本次更新主要完善了企业支付,对回调进行了优化,并增加了统一回调的最佳实践实例。
仓库地址
gitee: https://gitee.com/felord/wecom-sdk
github: https://github.com/NotFound403/wecom-sdk
特性
支持多企业微信同时配置作业集成方便,适用于各种Java生态目前实现企业微信接口200多个,能满足大部分企业微信业务场景的需求全参数封装,入参、出参高度语义化封装,再也不担心组织参数、解析参数的问题实现统一回调,所有回调事件可集中异步处理,开发者只需要关心业务逻辑的开发由 SDK 接管 AccessToken 生命周期,开发者无需关心 Token 的管理。 Maven 中央仓库坐标
普通版本 <dependency> <groupId>cn.felord</groupId> <artifactId>wecom-sdk</artifactId> <version>1.1.1</version> </dependency> 响应式版本 <dependency> <groupId>cn.felord</groupId> <artifactId>rx-wecom-sdk</artifactId> <version>1.1.1</version> </dependency> 采用技术栈
Retrofit2Rxjava3Okhttp4Jackson2XStream 🚀1.1.1 更新
实现企业支付-对外收款账户管理API优化了回调处理、完善了部分回调事件优化了应用管理-应用详情API增加回调最佳实践实例
目录
1、配置文件作用
2、配置文件的格式
1、application.properties 配置文件 - 效果演示
2、application.yml 配置文件 - 效果演示
为配置⽂件安装提示插件 - 社区版 idea
application.properties 配置文件说明
properties 基本语法
查看更多系统配置项 - properties
读取配置⽂件 - propertices
properties 格式配置文件的 缺点分析
application.yml 配置⽂件说明
yml 基本语法
yml的优点:解决 properties的缺点问题(代码冗余度高)
yml 使⽤进阶:yml 配置不同数据类型及 null
读取配置⽂件 - yml
拓展:注意事项
value 值加单双引号 - yml配置文件中,关于数据的单双引号的问题。
配置对象 - yml 配置文件
读取对象 - yml 配置对象
配置集合 - yml
Properties VS yml 总结
拓展:Spring Boot 有几种读取配置文件的方法?
1、配置文件作用 整个项目中所有重要的数据都是在配置文件中配置的。
比如:
1、数据库的连接信息(包含用户名和密码的设置)
2、项目的启动端口
在浏览这篇文章之间要先安装好kibana和elasticsearch,未安装的可以访问这个文章
快速安装elasticsearch
如果已经安装了则要启动这两个服务,通过浏览器访问进入到控制台
使 用Kibana 对 索 引 库 操 作 1.创建索引库: PUT /索引库名
2.查看索引库: GET /索引库名
3.删除索引库: DELETE /索引库名
在将索引库删除后再查询时查不到会报错的
使用kibana对类型及映射操作 1.创建字段映射 : PUT /索引库名/_mapping/typeName { "properties": { "字段名": { "type": "类型", "index": true, "store": false, "analyzer": "分词器" } } } 在创建映射之前要先把映射的库创好,不然会报错 2.查看映射关系
所有: GET /索引库名/_mapping
单个: GET /索引库名/_mapping/类型名
3.一次创建索引库和类型
数据类型 字段数据类型介绍:每个字段都有一个字段数据类型或字段类型。此类型指示字段包含的数据类型(如字符串或布尔值)及其预期用途。例如,可以将字符串索引到text字段和keyword字段。但是,text字段值将被分析用于全文搜索,而keyword字符串则保留原样用于过滤和排序。
字段类型按族分组。同一族中的类型具有完全相同的搜索行为,但可能具有不同的空间使用或性能特征,目前,有两个类型族,keyword和text。其他类型族只有一个字段类型。例如,boolean类型族由来一种字段类型组成:boolean
分类 string类型 Numerical数值类型 Date日期类型
Array数组类型 Object对象 ip地址
数组 多领域
本文目录 1. Docker 基础命令1.1 启动 docker1.2 关闭 docker1.3 重启 docker1.4 开机启动 docker1.5 查看 docker 运行状态1.6 查看 docker 版本信息1.7 查看 docker 系统信息,包括镜像和容器数1.8 docker 帮助命令 2. Docker 镜像命令2.1 查看自己服务器中 docker 镜像列表2.2 搜索镜像2.3 拉取镜像(从 Docker 镜像仓库获取镜像)2.4 运行镜像2.5 删除镜像2.6 保存镜像2.7 加载镜像2.8 镜像标签 3. Docker 容器命令3.1 查看正在运行容器列表3.2 查看所有容器3.3 运行容器3.4 停止容器3.5 删除容器3.6 容器端口与服务器端口映射3.7 进入容器3.8 从容器内退出到自己的服务器3.9 启动容器3.10 重启容器3.11 kill 容器3.12 容器文件拷贝3.13 查看容器日志3.14 设置开机自动启动容器3.15 更换容器名3.16 导出和导入3.17 在容器和主机之间复制文件/文件夹 1. Docker 基础命令 1.1 启动 docker systemctl start docker 1.2 关闭 docker systemctl stop docker 1.
1、前期准备 (1) 有数据的MongoDB数据库old_db、空数据库new_db
(2) 准备好MongoDB Tools
前往页面:https://www.mongodb.com/try/download/database-tools
选择所需版本下载并解压到自己想要的目录中:
2、将数据库old_db中的数据备份导出 (1) 对old_db右键,选择MongoDump
(2) 找到MongoDump.exe(从Mongo Tools中解压出来的:mongodump.exe)
(3) 选择自己想要存放数据的路径(假设为F:\mongoDB_backup),以gz格式存放。压缩后文件大小会只有:10%的样子。
3、将来自old_db的集合test_data导入到new_db (1) 对new_db右键,选择MongoRestore
(2) 选择以gz格式,在F:\mongoDB_backup中取出test_data.gz导入 部分参考:Navicat导入、导出MongoDB的集合
1、在pom.xml文件中添加MyBatis和MyBatis-Spring的依赖: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.wnhz.market</groupId> <artifactId>wn-market</artifactId> <version>1.0-SNAPSHOT</version> <!-- 版本说明--> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <!--起步依赖--> <parent> <artifactId>spring-boot-starter-parent</artifactId> <groupId>org.springframework.boot</groupId> <version>2.5.14</version> </parent> <!--项目依赖--> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!--数据库--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--数据源--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.18</version> </dependency> <!--mybatisplus组件--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <!--spring的单元测试--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> </dependencies> <!--项目打包--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> 2、创建application.
目录
介绍
单臂路由实现VALN间通信
一、VLAN配置 二、单臂路由的配置
1、SW1二层交换机
2、在R1上配置单臂路由
3.验证
二、三层交换实现VLAN间通信
1、VLANIF接口
(1)VLANIF接口是一种三层的逻辑接口,支持VLAN Tag的剥离和添加,因此可以通过VLANIF接口实现 VLAN之间的通信。
(2)VLANIF接口编号与所对应的VLAN ID相同,如VLAN 10对应VLANIF 10。
案例:三层交换实现VLAN间通信
一、基础配置(同上)
二、VLANIF接口配置
验证
介绍 1、子接口
(1)子接口(Sub-Interface)是基于路由器以太网接口所创建的逻辑接口,以物理接口ID+子接口ID进 行标识,子接口同物理接口一样可进行三层转发。
(2)子接口不同于物理接口,可以终结携带VLAN Tag的数据帧。
(3)基于一个物理接口创建多个子接口,将该物理接口对接到交换机的Trunk接口,即可实现使用一个 物理接口为多个VLAN提供三层转发服务。
2、子接口的应用配置 子接口应用与单臂路由,在实现VLAN间通信的时候,只使用一个物理接口即可实现成为单臂路由。 单笔路由配置步骤:
(1)创建子接口
(2)绑定VLAN-ID
(3)配置IP地址
(4)启用arp广播(arp作用:根据IP地址转换MAC地址)
单臂路由实现VALN间通信 配置如下:
一、VLAN配置 在R1,S1上配置:
vlan batch 10 20
二、单臂路由的配置 1、SW1二层交换机 interface Ethernet0/0/22
port link-type trunk
port trunk allow-pass vlan 10 20
2、在R1上配置单臂路由 (1)创建子接口
(2)绑定VLAN-ID
(3)配置IP地址
(4)启用arp广播 interface G0/0/0.10
dot1q termination vid 10
ip address 10.
达人探店 一、发布探店笔记 发布探店笔记功能是项目本身就完成了的功能,他会把图片存在本地,有兴趣可以去看源码,在UploadCOntroller类下
二、查看探店笔记 这个功能项目本身是没有完成这个接口的,所以需要我们自己去完成。
三、点赞功能 项目本身已经实现了点赞功能
项目原本的写法是通过点击点赞标识,直接向数据库发起请求,更新liked字段,并没有加任何判断。
这样看似没问题,但是却不符合逻辑,因为一个用户可以对同一篇笔记多次点赞,而现实应该是点一次赞,再点一次取消赞。
所以我们需要根据下面的需求更新代码:
使用redis的ZSet集合存储(key:被点赞的博客id,value:点赞的用户id)
使用Zset是为了后面方便按照用户的点赞时间排序(展示最先点赞的5个用户)
/** * 点赞功能 * * @param id * @return */ @Override public Result likeBlog(Long id) { ZSetOperations<String, String> opsForZSet = stringRedisTemplate.opsForZSet(); //1.获取当前登录用户 UserDTO user = UserHolder.getUser(); //2.判断当前用户是否在点赞列表中 String key = "blog:liked:" + id; Double score = opsForZSet.score(key, user.getId().toString()); if (score == null) { //3.如果不在,则点赞 //3.1 数据库对应blog的点赞数+1 boolean isSuccess = this.update().setSql("liked = liked + 1").eq("id", id).update(); //3.1 redis中blog对应的set集合添加当前用户 if (isSuccess) { opsForZSet.
对于大部分程序员,C语言是学习编程的第一门语言,很少有不了解C的程序员。
C语言除了能让你了解编程的相关概念,带你走进编程的大门,还能让你明白程序的运行原理,比如,计算机的各个部件是如何交互的,程序在内存中是一种怎样的状态,操作系统和用户程序之间有着怎样的“爱恨情仇”,这些底层知识决定了你的发展高度,也决定了你的职业生涯。
如果你希望成为出类拔萃的人才,而不仅仅是码农,这么这些知识就是不可逾越的。也只有学习C语言,才能更好地了解它们。有了足够的基础,以后学习其他语言,会触类旁通,很快上手,7 天了解一门新语言不是神话。
C语言概念少,词汇少,包含了基本的编程元素,后来的很多语言(C++、Java等)都参考了C语言,说C语言是现代编程语言的开山鼻祖毫不夸张,它改变了编程世界。
正是由于C语言的简单,对初学者来说,学习成本小,时间短,结合本教程,能够快速掌握编程技术。
在世界编程语言排行榜中,C语言、Java 和 C++ 长期霸占着前三名,加上近几年爆火的 Python,四门语言的市场占用率之和接近 50%,拥有绝对优势,如下表所示:
在 2017 和 2019 年,由于小型软件设备的蓬勃发展以及汽车行业底层软件的增加,C语言还拿下了「年度编程语言」的桂冠,成为全球增长最快的编程语言。下表列出了最近 10 年的“年度编程语言”:
C语言诞生于20世纪70年代,年龄比我们都要大,我们将在《C语言的三套标准:C89、C99和C11》一节中讲解更多关于C语言的历史。
当然,C语言也不是没有缺点,毕竟是70后老人,有点落后时代,开发效率较低,后来人们又在C语言的基础上增加了面向对象的机制,形成了一门新的语言,称为C++,我们将在《
C语言和C++到底有什么关系》中讲解。
C语言难吗? 和 Java、C++、Python、C#、JavaScript 等高级编程语言相比,C语言涉及到的编程概念少,附带的标准库小,所以整体比较简洁,容易学习,非常适合初学者入门。
编程语言的发展大概经历了以下几个阶段:
汇编语言 --> 面向过程编程 --> 面向对象编程
汇编语言是编程语言的拓荒年代,它非常底层,直接和计算机硬件打交道,开发效率低,学习成本高;C语言是面向过程的编程语言,已经脱离了计算机硬件,可以设计中等规模的程序了;Java、C++、Python、C#、PHP 等是面向对象的编程语言,它们在面向过程的基础上又增加了很多概念。 C语言出现的时候,已经度过了编程语言的拓荒年代,具备了现代编程语言的特性,但是这个时候还没有出现 “软件危机” ,人们没有动力去开发更加高级的语言,所以也没有太复杂的编程思想。
也就是说,C语言虽然是现代编程语言,但是它涉及到的概念少,词汇少,思想也简单。C语言学习成本小,初学者能够在短时间内掌握编程技能,非常适合入门。
C语言是计算机产业的核心语言 也许是机缘巧合,C语言出现后不久,计算机产业开始爆发,计算机硬件越来越小型化,越来越便宜,逐渐进入政府机构,进入普通家庭,C语言成了编程的主力军,获得了前所未有的成功,操作系统、常用软件、硬件驱动、底层组件、核心算法、数据库、小游戏等都使用C语言开发。
雷军说过,站在风口上,猪都能飞起来;C语言就是那头猪,不管它好不好,反正它飞起来了。
C语言在计算机产业大爆发阶段被万人膜拜,无疑会成为整个软件产业的基础,拥有核心地位。
软件行业的很多细分学科都是基于C语言的,学习数据结构、算法、操作系统、编译原理等都离不开C语言,所以大学将C语言作为一门公共课程,计算机相关专业的同学都要学习。
C语言被誉为“上帝语言”,它不但奠定了软件产业的基础,还创造了很多其它语言,例如 PHP、Python 等都是用C语言开发出来的,虽然平时做项目的时候看不到C语言的影子,但是如果想深入学习 PHP 和 Python,那就要有C语言基础了。C++ 和 Objective-C 干脆在C语言的基础上直接进行扩展,增加一些新功能后变成了新的语言,所以学习 C++ 和 Objective-C 之前也要先学习C语言。 C语言是有史以来最为重要的编程语言:要进入编程行业高手级别必学C语言,要挣大钱必学C语言,要做黑客、红客必学C语言,要面试名企、外企、高薪职位必学C语言。
目录
为 TiDB 落盘文件开启加密
日志脱敏
TiDB 组件日志脱敏
TiKV 组件日志脱敏
PD 组件日志脱敏
TiFlash 组件日志脱敏
TiDB 密码管理
密码复杂度策略
配置密码复杂度策略
开启密码复杂度策略检查
设置不允许密码与当前用户名相同
设置密码复杂度的检查等级
设置密码最小长度
设置密码字符规则
设置密码字典功能
密码重用策略
全局级别密码重用策略
账户级别密码重用策略
密码连续错误限制登录策略
配置密码连续错误限制登录策略
锁定账户解锁
密码过期策略
手动密码过期
自动密码过期
全局级别自动密码过期
账户级别自动密码过期
密码过期策略检查机制
密码过期处理机制
开启加密通信传输
TiUP组件开启TLS加密通信传输(推荐)
缩容PD节点
为集群开启TLS
验证已开启TLS
扩容PD节点
检查集群存在的潜在风险:
自动修复集群存在的潜在风险:
执行 scale-out 命令扩容 TiDB 集群:
开启TLS后的PD DashBoard使用
为 TiDB 落盘文件开启加密 当系统变量 tidb_enable_tmp_storage_on_oom 为 ON 时(默认为ON),如果单条 SQL 语句的内存使用超出系统变量 tidb_mem_quota_query 的限制,某些算子可以将执行时的中间结果作为临时文件落盘保存,直到查询执行完成之后将它们删除。
用户可以开启落盘文件加密功能,防止攻击者通过读取临时文件来访问数据。
修改tidb配置文件 vim /datalist/tidb-deploy/tidb-4000/conf/tidb.toml 添加如下配置([security]段若已存在,不要重复添加):
[security] spilled-file-encryption-method = "
目录
主节点修改配置文件
从节点修改配置文件 启动主从节点
验证redis主从模式
查看进程(所有主从主机分别查看启动结果)
登录主节点客户端验证
登录从节点进行验证
主从切换
主从模式下,主节点宕机,从节点无法自动升级为主节点,需要人为干预。分别在两台主机上进行安装,安装过程与单机模式相同,不再赘述。以下配置内容,均在单机模式的基础上进行增加额外的配置。 主节点修改配置文件 如要为redis设定密码,则在配置文件redis.conf中添加requirepass XXXXXX和masterauth XXXXXX,其中XXXXXX即为密码。
masterauth作用:主要是针对master对应的slave节点设置的,在slave节点数据同步的时候用到。requirepass作用:对登录权限做限制,redis每个节点的requirepass可以是独立、不同的。建议两个密码设置为相同密码,防止因为对应关系错误导致无法正常使用 如:
从节点修改配置文件 如主节点配置了master密码,则从节点也许对应设置,在配置文件redis.conf中添加requirepass XXXXXX和masterauth XXXXXX,其中XXXXXX即为密码。 masterauth作用:主要是针对master对应的slave节点设置的,在slave节点数据同步的时候用到。requirepass作用:对登录权限做限制,redis每个节点的requirepass可以是独立、不同的。建议两个密码设置为相同密码,防止因为对应关系错误导致无法正常使用 如:
从节点配置主节点同步信息 找到replicaof配置信息(大约在479行),去除注释并配置主节点信息如下:
replicaof 10.8.15.102 6379 启动主从节点 指定配置文件启动(分别启动主从节点)
/opt/tools/redis-6.2.7/src/redis-server /opt/tools/redis-cluster/redis.conf 验证redis主从模式 查看进程(所有主从主机分别查看启动结果) ps -ef|grep redis 登录主节点客户端验证 /opt/tools/redis-6.2.6/src/redis-cli -h 10.8.10.125 -p 6379 若有设置密码,则auth 密码进入
查看集群信息 info Replication 创建key进行测试 #创建key set name "test" #获取key get name 登录从节点进行验证 查看集群信息 info Replication 获取主节点创建的key进行测试 #获取key get name 可正确获取,表明主从建立成功
主从切换 redis的主从模式,不支持自动切换主从节点。意味着当主节点宕机后,需要手动切换为主节点;主节点恢复后,也需要手动切换原从节点为从节点。
关闭主节点,模拟主节点宕机 shutdown save 手动关闭从节点复制功能,使其临时变更为单机模式。 slaveof no one 再次查看主从信息,可以看到从节点已变为主
0、引言 Qt 的官方文档网站提供了 Qt 不同发行版本的平台支持情况,比如我们可以查看 Qt 6.5 LTS 支持平台:
(可以看到,Qt 6.5 LTS 的支持平台是 Ubuntu 22.04)
笔者使用的操作系统是 Ubuntu 20.04,其推荐安装的最新的 Qt 发行版本为 Qt 6.4 或 Qt 6.2 LTS;笔者更倾向于安装 LTS(长期支持)版本,所以本文将着手探讨如何在 Ubuntu 20.04.6 操作系统上安装 Qt 6.2 LTS。
💬 如果您的计算机还没有安装 Ubuntu 20.04.6 的话,可以参考这篇文章。
当然,Qt 的官方文档网站也提供了 Qt 的详尽安装教程,所以本文从本质上来说也只是搬运/转载。
⚠️ 从 Qt 5.15 开始,Qt 公司不再提供开源离线安装程序(open source offline installer)。但我们仍然可以通过在线安装程序在开源许可证下下载、安装和使用最新的 Qt 框架。
Qt 框架可以在开源和商业许可下使用。这种双重许可模式基于交换条件原则 —— 大致意思是“以物换物”。简单地说,它是这样工作的:作为使用 Qt 创建应用程序所获得的价值的回报,您需要通过贡献 Qt 或购买 Qt 来回馈。
所谓“贡献 Qt”,即在为您的项目选择开源许可证时,您可以通过以下任意一个许可证来使用 Qt 并为自由和开源软件开发做出贡献:LGPL 版本3,GPL 版本2和 GPL 版本3。您可以在 Qt 官网的开源下载页面查看更多信息。
一、基本概念 DBSCAN的基本概念可以用1,2,3,4来总结。
1个核心思想:基于密度 直观效果上看,DBSCAN算法可以找到样本点的全部密集区域,并把这些密集区域当做一个一个的聚类簇。
2个算法参数:邻域半径R和最少点数目minpoints 这两个算法参数实际可以刻画什么叫密集——当邻域半径R内的点的个数大于最少点数目minpoints时,就是密集。
3种点的类别:核心点,边界点和噪声点 邻域半径R内样本点的数量大于等于minpoints的点叫做核心点。不属于核心点但在某个核心点的邻域内的点叫做边界点。既不是核心点也不是边界点的是噪声点。
4种点的关系:密度直达,密度可达,密度相连,非密度相连 如果P为核心点,Q在P的R邻域内,那么称P到Q密度直达。任何核心点到其自身密度直达,密度直达不具有对称性,如果P到Q密度直达,那么Q到P不一定密度直达。
如果存在核心点P2,P3,……,Pn,且P1到P2密度直达,P2到P3密度直达,……,P(n-1)到Pn密度直达,Pn到Q密度直达,则P1到Q密度可达。密度可达也不具有对称性。
如果存在核心点S,使得S到P和Q都密度可达,则P和Q密度相连。密度相连具有对称性,如果P和Q密度相连,那么Q和P也一定密度相连。密度相连的两个点属于同一个聚类簇。
如果两个点不属于密度相连关系,则两个点非密度相连。非密度相连的两个点属于不同的聚类簇,或者其中存在噪声点。
二,DBSCAN算法 1.算法描述 DBSCAN 算法对簇的定义很简单,由密度可达关系导出的最大密度相连的样本集合,即为最终聚类的一个簇。
DBSCAN 算法的簇里面可以有一个或者多个核心点。如果只有一个核心点,则簇里其他的非核心点样本都在这个核心点的 Eps 邻域里。如果有多个核心点,则簇里的任意一个核心点的 Eps 邻域中一定有一个其他的核心点,否则这两个核心点无法密度可达。这些核心点的 Eps 邻域里所有的样本的集合组成一个 DBSCAN 聚类簇。
DBSCAN算法的描述如下。
输入:数据集,邻域半径 Eps,邻域中数据对象数目阈值 MinPts;
输出:密度联通簇。
处理流程如下。
1)从数据集中任意选取一个数据对象点 p;
2)如果对于参数 Eps 和 MinPts,所选取的数据对象点 p 为核心点,则找出所有从 p 密度可达的数据对象点,形成一个簇;
3)如果选取的数据对象点 p 是边缘点,选取另一个数据对象点;
4)重复(2)、(3)步,直到所有点被处理。
DBSCAN 算法的计算复杂的度为 O(n²),n 为数据对象的数目。这种算法对于输入参数 Eps 和 MinPts 是敏感的。
2. 算法实例 下面给出一个样本数据集,如表 1 所示,并对其实施 DBSCAN 算法进行聚类,取 Eps=3,MinPts=3。
数据集中的样本数据在二维空间内的表示如图 3 所示。
图 3 直接密度可达和密度可达示意
日志技术具备的优势
可以将系统执行的信息选择性的记录到指定的位置(控制台、文件中、数据库中)。·
可以随时以开关的形式控制是否记录日志,无需修改源代码。
日志体系结构
Logback日志框架
Logback是由log4j创始人设计的另一个开源日志组件,性能比log4j要好
Logback是基于slf4j的日志规范实现的框架。
Logback主要分为三个技术模块:
logback-core: logback-core 模块为其他两个模块奠定了基础,必须有。
logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API。
logback-access模块与Tomcat和Jetty 等servlet容器集成,以提供HTTP访问日志功能
使用Logback需要使用哪几个模块,各自的作用是什么。
slf4j-api:日志规范
logback-core:基础模块。
logback-classic:它是log4j的一个改良版本,同时它完整实现了slf4j API
这些都可以去Logback或slf4j官方网站下载
使用Logback
完成这些步骤便可使用日志对象输出日志信息:
public class Test { //创建LogBack对象 public static final Logger LOGGER=LoggerFactory.getLogger("Test.class"); public static void main(String[] args) { try { LOGGER.debug("main开始执行"); LOGGER.info("第二行日志"); int a=10,b=0; LOGGER.trace("a="+a); LOGGER.trace("b="+b); System.out.println(a/b); } catch (Exception e) { e.printStackTrace(); LOGGER.error("发生错误,"+e); } } } logback.xml文件:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- CONSOLE :表示当前的日志信息是可以输出到控制台的。 --> <appender name="CONSOLE" class="
1.简介 在实际应用中,有时候我们需要创建一些个延迟的、并具有周期性的任务,比如,我们希望当我们的程序启动后每隔1小时就去做一次日志记录、每天凌晨12点去清理一下数据库中的过期数据等。在JDK中提供了两种方法去创建延迟周期性任务。分别是ScheduledThreadPoolExecutor和Timer。另外还有一个开源的更加强大的任务调度框架Quartz。下面我们来具体认识这三个框架。
2.Timer Timer的主要方法有:
// 安排在指定的时间执行 void schedule(TimerTask task, Date time); // 安排在指定的时间开始以重复的延时执行 void schedule(TimerTask task, Date firstTime, long period); // 安排在指定的延迟后执行 void schedule(TimerTask task, long delay); // 安排在指定的延迟后开始以重复的延时执行 void schedule(TimerTask task, long delay, long period); // 安排在指定的时间开始以重复的速率执行 void scheduleAtFixedRate(TimerTask task, Date firstTime, long period); // 安排在指定的延迟后开始以重复的速率执行 void scheduleAtFixedRate(TimerTask task, long delay, long period); //可以在任何时刻调用cancel方法终止timer线程 cancel(); //从任务队列中删除已取消的任务,返回删除的数量 int purge(); 注:重复的延时和重复的速率的区别在于,前者是在前一个任务的执行结束后间隔period时间再开始下一次执行;而scheduleAtFixedRate则是会尽量按照任务的初始时间来按照间隔period时间执行。如果一次任务执行由于某些原因被延迟了,用schedule()调度的后续任务同样也会被延迟,而用scheduleAtFixedRate()则会快速的开始两次或者多次执行,是后续任务的执行时间能够赶上来。
3.ScheduledThreadPoolExecutor **ScheduledThreadPoolExecutor的主要方法:
// 在指定的延迟后执行 <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) // 在指定的延迟后执行 ScheduledFuture<?
这一章节开始我们讲解各种外设的控制,包括gpio,i2c,dma等等,既然是外设,那就涉及到具体的目标板,博主在这里使用的开发板是开源平台beagle bone green,内核版本为4.14.
今天我们来讲解gpio的设备驱动程序。
gpio相关的库函数 为了linux的可移植性和统一,linux提供一套函数库供用户使用,内容涵盖了GPIO/I2C/SPI等外设的控制,关于函数库可以参考官方网站
这一章我们需要用到gpio相关的库函数:
//检查gpio number是否合法 int gpio_to_irq(unsigned gpio) //根据gpio number申请gpio资源,label为gpio名称 int gpio_request(unsigned gpio, const char *label) //释放gpio 资源 void gpio_free(unsigned gpio) //设置gpio 为输入 int gpio_direction_input(unsigned gpio) //设置gpio 为输出 int gpio_direction_output(unsigned gpio, int value) //设置gpio的值 gpio_set_value(unsigned gpio, int value) //设置gpio的消抖时间,主要用于按键消抖 int gpio_set_debounce(unsigned gpio, unsigned debounce) //获取gpio对应的中断线路 int gpio_to_irq(unsigned gpio) //gpio中断,当产生中断时调用handle函数 int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char * name, void * dev) linux gpio设备驱动程序 在前面的章节我们知道了怎么写一个字符设备驱动程序的框架,现在我们就只需要往框架里面添加相应的处理代码就可以了。
问题:
酒馆做活动,1块钱喝一瓶啤酒,2个空瓶可以兑换一瓶啤酒,
4个瓶盖可以兑换一瓶啤酒。如果有15块钱,最多可以喝多少瓶啤酒?
写个程序来计算,输入n元钱,输出可以喝多少瓶酒的数量(不允许借用)
解题思路:
模拟过程一步一来,代码如下
# had = { # "瓶子": 0, # "盖子": 0 # } # # def have(monry): # # 手里有多少钱就等于你喝了多少酒且拥有相同数量的瓶子和盖子(n是你喝的酒 # had["瓶子"] = monry # had["盖子"] = monry # n = monry # print("此时我花了{}钱,买了{}瓶酒,我现在有{}个瓶子,{}个盖子".format(monry, monry, monry, monry)) # while True: # if had["瓶子"] >= 2: # a = had["瓶子"] // 2 # print("我现在有{}个瓶子,{}个盖子。 老板我先给你{}个瓶子,你给我{}瓶酒把".format(had["瓶子"], had["盖子"], 2 * a, a)) # had["瓶子"] = had["瓶子"] - 2 * a # had["
文章目录 前言部署前准备:打包两个Vue项目nginx中的配置 准备后端代码 服务器环境搭建一,安装mysql和redis二,安装python(有坑)三,安装uwsgi以及配置nginx中的配置 四,安装daphne + superviors以及配置 (目的是让Websocket正常使用)nginx中的配置 前言 使用到的所有技术栈:
Vue+ Django + DRF + Celery + Websocket + Mysql + Redis + nginx + uwsgi + daphne + supervisor
自己项目用到的东西比较多,在部署服务器也是踩过无数次的坑,今天来整理一下自己部署项目的全部流程。
自己主要学的后端,所以这里只是讲述了我部署项目的一个流程和踩过的坑。目前对于部署用到的技术栈不是很熟悉,所以哪里说错了还请大神勿喷。如果你对哪里有疑问或者自己不同的见解,非常欢迎和我一起探讨
部署前准备: 打包两个Vue项目 npm run build
Vue打包配置文件内容(vue.config.js)
const { defineConfig } = require('@vue/cli-service') module.exports = defineConfig({ transpileDependencies: true, outputDir:'../打包项目/resume1', // 打包文件存放的路径 publicPath:'/resume/' // 这个是项目在服务器的路径 }) 避坑:publicPath路径是路由后边的路径,不是相对于根目录的路径。举个例子
域名地址:project.com
project.com 可以直接访问项目一,
project.com/resume/ 访问项目二,
那第一个项目的publiPath值为’/‘,第二个就为’/resume/’
注意:publicPath的地址和项目在服务器的实际路径没有关系,实际路径是需要nginx去配置的
我就是把publicPath写成了项目在服务器根目录的相对路径,然后每次打包后都是白屏。
nginx中的配置 root /www/server/nginx/html; location /EditResume { // 第二个项目 alias /www/server/nginx/html/pluging/EditResume; try_files $uri $uri/ /EditResume/index.
查找算法 顺序查找 def linear_search(li, val): for i, idx in enumerate(li): if i == val: return idx return None 时间复杂度:O(n)
二分查找 def binary_search1(lis, val): left = 0 right = len(li) - 1 while left < right: mid = (left + right) // 2 if val == li[mid]: return mid elif val > li[mid]: left = mid + 1 elif val < li[mid]: right = mid - 1 else: return None # 递归查找 def binary_search2(lis, val): l = 0 r = len(lis) - 1 mid = (l + r) // 2 print(val, mid, lis[mid], lis[-1], lis[0]) if val == lis[mid]: return True elif val > lis[mid]: return binary_search2(lis[mid + 1:], val) else: return binary_search2(lis[:mid], val)
安装 安装node node自带npm
如果已经全局安装过旧版本的vue-cli npm uninstall vue-cli -g //yarn global remove vue-cli
安装vue-cli3(需要安装3.x以上版本) npm install -g @vue/cli
安装vue3以下版本的脚手架,命令 npm install -g vue-cli@版本号
安装3以上版本的脚手架 npm install -g @vue/cli@版本号
全局安装3以上版本的脚手架 npm install -g @vue/cli-init
全局安装webpack npm install webpack -g
babel是转码器,将es6,es7转成浏览器能识别的es5
@vue/cli3与vue-cli2的区别 @vue/cli3和vue-cli2的区别在于:
创建项目 vue create (vue/cli3) vue init webpack appname(vue-cli2)
启动项目 由npm run dev 改成 npm run serve
移除了配置文件目录 config 和 build 文件夹,如果需要自定义配置,需要自己新建vue.config.js文件
移除了 static 静态资源文件夹,新增 public 文件夹,静态资源转移到public目录中,通过/xx.xx可以直接访问,并且 index.html 移动到 public 中
目录 问题描述解决方式 问题描述 dpkg was interrupted, you must manually run ‘sudo dpkg --configure -a’ to correct the problem.
解决方式 参考:https://askubuntu.com/questions/163200/e-dpkg-was-interrupted-run-sudo-dpkg-configure-a
运行:
sudo dpkg --configure -a
目录
一、实验目的
二、设计要求
三、实验代码
1.顶层文件代码
2.仿真文件部分代码
3.系统工程文件
四、实验结果及分析
1、引脚锁定
2、仿真波形及分析
3、下载测试结果及分析
五、实验心得
一、实验目的 (1)掌握通信信号调制过程及实现原理;
(2)了解设计中的优化方案;
(3)进一步学习复杂数字系统设计;
(4)培养工程思维及创新思维。
二、设计要求 (1)实现单路PWM 信号模块,可通过端口设置初始相位,频率,占空比;
(2)通过模块调用方法,实现三路PWM信号输出,分辨展示相位,频率,占空比可调;
(3)加入正弦波形VTH(t)实现SPWM波形;
三、实验代码 1.顶层文件代码 限于篇幅,此处仅给出顶层代码
`timescale 1ns / 1ps module PWM1( input clk, //systerm clock 50MHz input rst_n, input fclock,//频率设置信号 input xclock ,//相位设置信号 input zclock,//占空比设置信号 input[1:0]f, input[1:0]x, input[1:0]z, output pwm1, output pwm2, output pwm3, output pwm4, //output [7:0]CNT2, //output [7:0]CNT2, //output [7:0]CNT3, //output [7:0]CNT4 output [9:0]dataout ); wire [7:0]CNT1; wire[7:0]CNT2; wire [7:0]CNT3; wire [7:0]CNT4; //wire [9:0]dataout; reg [19:0]count=0; reg [30:0]count2=0; reg [2:0] sel=0; parameter T1MS=50000; //仿真 //wire clk1; //assign clk1=clk; //板子 reg clk1; always @(posedge clk) begin count2=count2+1; if(count2/100000%2==1) begin clk1=1'b1; count2=0;end else clk1=1'b0; end //频率变换 pwm_gen U1(.
一:使用默认Objects.equals()进行比较,将比较两个对象的地址,相同返回true,不同则false; public class Main { public static void main(String[] args) { String c="111"; int d=12; Person man=new ChangShi(c,d);//("姓名",id) Person woman=new ChangShi(c,d); System.out.println(man.equals(woman));//由于我们没有重写equals函数,所以这两行结果相同 System.out.println(Objects.equals(man,woman)); } } 输出结果:false false 二:'=='默认比较地址,在String,Date,File等类中equals()方法进行了重写,并且调出Objects类源码如下 public static boolean equals(Object a, Object b) { return (a == b) || (a != null && a.equals(b)); } public class Main{ public static void main(String[] args){ String a=new String("111"); String b="111"; String c="111"; int d=12; System.out.printf("a和b用'=='比较:%b\n",a==b); System.out.printf("a和b用'equals()'比较:%b\n",b.equals(a)); System.out.printf("a和b用'Objects.equals()'比较:%b\n",Objects.equals(b,a)); } } 输出结果:false true true//根据Objects.
下载:Fiddler | Web Debugging Proxy and Troubleshooting Solutions
安装:下载完成后,默认安装即可
使用:双击Fiddler.exe进入界面
设置是否抓包(默认时开启的)
表头介绍:序号、HTTP状态码、请求使用的协议,如HTTP/HTTPS/FTP等、请求地址的主机名、请求资源的位置、该请求的大小、请求的缓存过期时间或者缓存控制值、请求响应的类型、发送此请求的进程:进程ID、允许用户为此回话添加备注、允许用户设置自定义值
图标含义:
: 服务端错误
:会话被客户端、Fiddler 或者服务端终止
:请求已经发往服务器
:已从服务器下载响应结果
:请求使用 HTTP 的 CONNECT 方法,使用 HTTPS 协议建立连接隧道
:请求使用 HTTP 的 POST 方法
:请求使用 HTTP 的 HEAD 方法,即响应没有内容(Body)
:响应是 HTTP/304(无变更):使用缓存文件
:响应是 JSON 格式
抓取手机数据包:
设置抓取HTTPS请求:Tools->Options->HTTPS->勾选Decrypt HTTPS traffic ->勾选Ignore server certificate errors->点击右边的Actions->选择Trust Root Certificate->Yes->OK
设置允许远程连接:Tools->Options->Connections->勾选Allow remote computers to connect->OK
重启Fiddler,点击右上角Online,查看本机ip
将电脑和手机连到同一个网络(WIFI)下
手机下载和安装证书:我的电脑ip为192.168.191.1,我通过手机访问http://192.168.191.1:8888后,会出现如下信息,然后点击FiddlerRoot certificate,下载FiddlerRoot.crt,然后点击安装,输入证书名称,选择VPN和应用作为凭证用途,然后点确定,至此证书安装完成。
为手机设置代理:设置->WLAN->长按已连接WIFI->修改网络->高级选项->手动->修改为以下页面内容
测试手机端抓包:成功抓取到了
下载:Inno Setup Downloads
安装:双击运行innosetup-6.2.2.exe,按照默认选择即可,下载完成后如图
使用:
双击运行Compil32.exe->File->New->填入自定义信息->Next
选择安装目录->Next
添加主程序文件、依赖文件->Next(如果没有主启动程序,例如是B/S的,就可以选择第二个勾勾)
应用程序图标设置->Next
许可证设置->Next
指定安装模式(和用户使用权限有关)->Next
指定语言->Next
安装程序的配置(如输出位置、安装程序名称、安装程序图标、密码)->Next
是否使用推荐的预处理器->Next
Finish
最终生成的脚本如图
编译脚本:点击Compile,然后会生成一个exe安装程序
双击此exe文件然后会弹出安装程序界面
查看安装好的文件内容
计算机网络是连接全球计算机的重要组成部分,本文详细介绍了计算机网络的基础知识,包括网络结构、通信协议、网络层次结构、TCP/IP协议族等内容。
1.前言 计算机网络作为现代信息时代的重要基础设施,已经渗透到我们生活的方方面面。它为人与人,人与计算机之间的信息交流提供了快速、便捷的方式,改变了我们工作、学习和生活的方式。本文将介绍计算机网络的概念和重要性,帮助读者更好地理解和利用计算机网络。
一、什么是计算机网络
计算机网络是由若干台计算机通过通信设备连接起来,共享资源、信息和服务的系统。它可以是局域网、广域网或互联网等不同范围的网络。计算机网络的基本组成部分包括计算机节点、通信介质和通信协议等。
二、计算机网络的组成
计算机节点:计算机节点是网络中的终端设备,可以是个人电脑、服务器、手机、路由器等。每个节点都有自己的唯一标识,用于在网络中进行识别和寻址。
通信介质:通信介质是计算机节点之间进行数据传输的媒体,如光纤、电缆、无线电波等。不同的通信介质具有不同的传输速率和传输距离。
通信协议:通信协议是计算机网络中设备之间进行通信的规则和约定。常见的协议有TCP/IP协议、HTTP协议、FTP协议等。它们规定了数据如何封装、传输和解封装,保证数据的可靠性和完整性。
三、计算机网络的重要性
信息交流:计算机网络使得人们可以在全球范围内快速、便捷地共享信息。通过互联网,我们可以与世界各地的人们进行实时的语音、视频交流,获取最新的新闻、知识和娱乐资源。
资源共享:计算机网络将不同计算机节点连接起来,使得资源可以共享和利用。通过共享打印机、共享文件服务器等,大大提高了工作效率,节省了资源开支。
商务应用:计算机网络为商务活动提供了强大的支持。在线购物、电子支付、电子商务等已经成为当今商业领域中不可或缺的组成部分。计算机网络极大地促进了商务的发展和扩展。
学习和教育:计算机网络为学生和教师提供了广阔的学习和教育资源。在线学习平台、远程教育等让知识不再受时空的限制,使得学习变得更加自由和灵活。
科学研究:计算机网络为科学研究提供了强大的支持。科学家们可以通过网络共享实验数据、合作研究、进行远程协同工作,从而加速了科学研究的进展
2.网络结构 在计算机网络中,客户-服务器模式是一种常见且重要的网络通信模式。它基于服务端(服务器)和客户端之间的相互交互,实现了资源共享、数据传输和应用服务等功能。本文将详细介绍客户-服务器模式的概念、工作原理以及应用场景,帮助读者更好地理解和应用这一网络模式。
一、什么是客户-服务器模式
客户-服务器模式是一种典型的分布式计算模型,其中服务器提供服务,并响应客户端的请求。在该模式下,客户端主动发送请求给服务器,服务器则处理请求并返回结果给客户端。客户-服务器模式广泛应用于互联网、企业内部网络和各种分布式系统中。
二、客户-服务器模式的工作原理
客户端:客户端是用户使用的终端设备,如个人电脑、手机等。客户端通过网络连接到服务器,并向服务器发送请求。
服务器:服务器是提供服务的主机,它接收来自客户端的请求,并根据请求内容进行相应的处理。服务器可以处理多个客户端的请求,并同时提供服务。
请求与响应:客户端向服务器发送请求时,请求包含了需要的服务或资源的描述。服务器接收到请求后,会进行相应的处理,并生成响应结果发送给客户端。
通信协议:客户-服务器通信依赖于一定的通信协议。常见的应用层协议有HTTP、FTP、SMTP等,它们定义了请求和响应消息的格式和内容,确保了数据的可靠传输。
资源共享:客户-服务器模式下,服务器可以提供各种资源的共享,如文件、数据库、打印机等。客户端可以通过请求获取到这些资源,并在本地使用或处理。
三、客户-服务器模式的应用场景
网络服务:Web服务器是客户-服务器模式的典型应用之一。通过HTTP协议,客户端可以向服务器请求并获取网页、图片、视频等资源。
数据库管理:数据库服务器通过客户-服务器模式提供数据存储和管理服务。客户端可以通过请求操作数据库,进行数据查询、修改等操作。
文件共享:文件服务器可以存储和管理大量的文件资源。客户端可以通过访问服务器,实现文件的上传、下载和共享。
邮件服务:电子邮件系统是基于客户-服务器模式的。客户端通过邮件客户端软件连接到邮件服务器,发送和接收电子邮件。
游戏服务:在线游戏往往采用客户-服务器模式,服务器负责游戏逻辑和数据管理,客户端负责用户界面和交互。
3.通信协议 计算机网络中的通信协议是实现网络通信的重要基础。本文将介绍计算机网络中常用的通信协议,从HTTP协议到TCP/IP协议,帮助读者全面了解不同层次的协议及其在网络通信中的作用。
一、HTTP协议
HTTP(Hypertext Transfer Protocol)是应用层协议,它定义了浏览器与Web服务器之间的通信规则。HTTP协议使用客户端-服务器模式,通过请求和响应传输超文本数据。通过HTTP协议,用户可以访问网页、下载文件等。
请求方法:HTTP协议定义了常见的请求方法,如GET、POST、PUT、DELETE等。这些方法定义了客户端对服务器资源的操作方式。
请求头和响应头:HTTP协议使用请求头和响应头传递辅助信息。请求头包含了客户端的相关信息,而响应头则包含了服务器返回的信息。
状态码:HTTP协议使用状态码表示请求的处理结果。常见的状态码有200表示成功,404表示未找到资源,500表示服务器内部错误等。
二、TCP/IP协议
TCP/IP协议是一组网络通信协议,它实现了互联网的核心功能。TCP/IP协议族包含了多个层次的协议,如网络接口层、网络层、传输层和应用层。
网络接口层:网络接口层负责将数据帧封装成比特流通过物理介质进行传输。常见的网络接口协议有以太网、无线局域网等。
网络层:网络层使用IP协议实现了数据包的传输,负责将数据从源主机发送到目标主机。IP协议定义了IP地址和路由选择算法。
传输层:传输层使用TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)协议,实现了可靠的端到端通信。TCP提供面向连接的可靠传输,而UDP提供无连接的不可靠传输。
应用层:应用层协议支持各种网络应用,如电子邮件(SMTP)、文件传输(FTP)、远程登录(Telnet)等。常见的应用层协议有HTTP、DNS、DHCP等。
三、其他常见协议
除了HTTP和TCP/IP协议,还有许多其他常见的通信协议:
FTP(File Transfer Protocol):用于在客户端和服务器之间进行文件传输。
SMTP(Simple Mail Transfer Protocol):用于电子邮件的发送。
POP3(Post Office Protocol version 3):用于电子邮件的接收。
DNS(Domain Name System):用于域名解析,将域名转换为IP地址。
DHCP(Dynamic Host Configuration Protocol):用于动态分配IP地址和其他网络配置信息。
目录
一、Linux常用命令
1)# 与 $ 提示的区别
2)ifconfig
3) su
4) cd
5) 目录查看
6) 查看文件内容
7)创建目录及文件
8)复制和移动
9)其他
10) tar
11) which
12) whereis
13) find
14) chmod
二、vim一般使用
三、SSH介绍
1) 什么是SSH
2)SSH服务端和客户端
3)基本工作机制
四、SSH密钥登录
1) 首先在服务器中创建密钥对
2)在服务器中安装公钥
3) 设置文件权限
5)重启ssh服务
一、Linux常用命令 1)# 与 $ 提示的区别 '#' 表示用户有root权限,一般的以root用户登录提示符为#
'$'提示符表示用户为普通用户
2)ifconfig 查看ip地址
eno1: 代表由主板bios内置的网卡ens1:代表主板bios内置的PCI_E网卡enp2s0: PCI-E独立网卡eth0: 如果以上都不用,则返回默认的网卡名 ens33则属于第二种类型,即说明你的网卡是内置的PCI-E网卡,
这是由网卡特性命名的可以在 /etc/sysconfig/network-scripts/ifcfg-ens33修改名字
如果提示“未找到命令”,则需要安装net-tools工具包。
(centos系统中运行: yum install net-tools)
3) su 命令格式
su 用户名 linux用户切换,切换到root用户需要输入密码。临时使用root权限使用 sudo
前言:在绝大部分系统中,我们需要记录各种操作人、操作时间或者是这条记录的创建人、创建时间。那么在本次学习中,我们就有这么四个字段:createUser/createTime和updateUser/updateTime并且没有抽取出BaseModel基础对象来抽象这几个字段,如果我们在每个代码中都手动去设置,那么则会有很多重复代码和重复工作量。那么MybatisPlus给我们提供了解决方案:元数据处理器(MetaObjectHandler)。
MybatisPlus版本:3.5.3.1
为什么3.5.3后面会有个 “.1” ?这又不得不说另外一个故事了...
之前使用MybatisPlus3.5.3的时候,由于我单表习惯性使用LambdaQueryChainWrapper对象来执行查询,某一天测试的时候,数据异常流转导致我想查的某条数据不存在,结果离奇的事情就来了:正常来说,查不到数据应该会返回null到Java中,但是3.5.3版本的LambdaQueryChainWrapper().one()查不到数据,则直接抛出了空指针异常,后来研究官方版本日志才发现这是3.5.3版本的问题,需要将版本更新至3.5.3.1,所以如果你经常使用LambdaQueryChainWrapper,一定要更新到3.5.3.1以避免这个问题,防止挨领导的批。
接下来,我会展示我三个版本的代码,而最终版本则是最终可用版,当然你也可以自己修改一下代码以实现对自己的业务系统的性能优化。 Step1:新建一个元数据处理器类。 直接上代码:
这里是一个我自己新建的插入更新字段处理器,需要继承MybatisPlus提供的MetaObjectHandler元数据处理器接口,这样就可以完成自定义元数据处理器的创建了。
这边我们主要处理插入和更新字段,所以需要重写两个方法:
1.insertFill(MetaObject metaObject):插入填充方法,MybatisPlus会识别每一个执行的Insert语句,然后执行这个方法去填充属性。
2.updateFill(MetaObject metaObject):更新填充方法,和插入一样的原理。
Step2:编写处理器代码逻辑。 首先,我们要明确我们的目标:在插入和更新时,填充相应字段。
那么就有了接下来的第一版代码:
第一版代码解析:
1. 首先我们校验登录状态和用户。
2. 通过接口提供的MetaObject对象获取源对象。
3. 获得源对象的class字节码对象。
4. 通过字节码对象获取属性对象数组Fields。
5. 循环判断属性对象名是否为对应的属性名。
6. 设置对应值。
总的来说:就是通过反射的方法把对应的值设置进去。
乍一看好像没毛病?
确实,这个方法确实能将update和insert对应的字段设置进去。
但是!我们知道反射是非常影响性能的!而且如果一个类有较多的属性,那会导致多次无用的循环,况且插入和更新属于热代码,在热代码路径上执行反射的操作,如果发生高并发情况,那造成的后果将会是灾难性的。
下面,我们先简单说一下反射到底为什么会影响性能?
反射是一种Java在运行时创建类、修改类、调用类方法、对对象属性读写的一种操作。
简单剖析一下反射影响性能开销的几个点:
1. 执行反射的第一步是对类的类型检查和解析:反射在运行时查找并调用方法或访问字段,此时需要进行动态解析,这会花费比常规方法调用或字段访问更多的时间。由于类型信息不是在编译期确定的,而是需要在运行期做许多额外的检查,包括类型检查,可能的动态分派等,这些都会增加处理的时间。
2. 跳过JVM优化:目前我们使用到的绝大部分JVM都会对常规的方法调用和字段访问进行优化,例如内联,死码消除等。但是,当我们使用反射时,这些优化在很大程度上被绕过,因为JVM无法预测和优化动态解析的行为。
3. 对象的创建:反射方法(如:Method.invoke())通常需求参数以对象形式传入,这可能导致需求创建额外的对象,而正常的方法调用则不需要。例如,如果调用的方法接受原始类型,必须要先将这些原始类型装箱成对象。同样,如果方法有返回值,那么返回的结果也需要进行拆箱操作,这些操作都会消耗额外的CPU周期时间。
以上这些开销对于单个接口单次调用来说可能开销不大,但是如上面所说,对于热代码高并发的接口,这些性能损耗将会是灾难性的。
Step3:优化反射带来的性能损耗。 首先,我们还是要明确目标:减少反射代码,减少反射对接口的性能开销。
思考:如何才能减少反射带来的性能开销呢?能不能不用反射就完成对类字段的读取和设值呢?
带着上面的问题,我想到第一个解决方案:高级反射。
什么是高级反射?高级反射是一个比较笼统的概念,例如使用Javassist库、CgLib、ReflectASM等库来实现一个ClassPool类池。这个学习成本较高,所以我们不选择这个方案。
第二个解决方案:缓存装载所有关于更新和插入的set方法。
这个方法就是通过缓存来实现快速查找值的setter方法。但是会造成内存开销。所以继续寻找更优解。
最终解决方案:MybatisPlus官方提供的getFieldValByName()和setFieldValByName()方法实现值的获取和设置。
Step4:应用解决方案。 应用了最终解决方案后,我们有了接下来的第二版代码:
上面这个代码起始已经能用了,但是由于我的系统中参数类型参差不齐,有的用Date有的用LocalDateTime,所以我们可以继续优化。
优化后的最终版代码:
这里使用instanceof判断了属性的类型,用于判断设置什么值进去,那么这段代码就是需求的完整版了。
接下来是源码深度思考和解析,可能会有点晦涩难懂,我自己在读源码时,也有很多迷茫不懂的地方,各位有兴趣的可以继续往下看。
最后的思考:为什么使用MybatisPlus自带的方法能提升性能?难道他里面使用的不是反射的方法吗? 带着这个问题,我们直接进入到源码中一探究竟。利用IDEA自带的debug模式,我们可以深度追踪源码调用链路。
直接上源码:
第一级(基础重点):调用metaObject的hasGetter(fieldName)的方法,判断是否存在getter方法。其中metaObject是该对象的元数据,我们点进其对应的类中可以发现,里面包含了多个对象属性:
1. 源对象(originalObject):
该对象是执行方法时的原始对象(可以是任何类型,比如你使用了OrderModel进行增和改操作,那么这个对象的类型就是OrderModel)
2. (重点)原始对象的包装类(objectWrapper):
负责对原始对象的操作,如获取属性值,设置属性值等。objectWrapper 还有几个实现子类,例如beanWrapper,mapWrapper,collectionWrapper,分别对应Bean,Map和Collection的包装。根据 originalObject 的类型,Mybaits会创建对应的 ObjectWrapper 实例。
文章目录 概述01 连接远程docker02 本地打包03 创建dockerfile文件04 部署并运行 概述 使用docker运行SpringBoot项目是一个不错的选择,传统方式需要手动打包并上传到服务器,再使用docker build构建镜像,再使用docker run启动运行,难免有些繁琐,本文介绍如何使用idea帮我们完成这些操作,简化操作流程。
01 连接远程docker (如上图)一般会默认带一个Docker,如果没有,点击+号创建一个Docker Connection
如果存在一个Dokcer连接,右键点击编辑配置。
无论是新增还是编辑配置,都选择SSH方式
输入服务器的ip、用户名和密码,创建一个SSH连接。
创建好后,点击连接按钮。(下图)
这样就连上服务器并可管理docker了。
02 本地打包 点击右侧的maven管理工具,再点击上方的skip tests model跳过测试。
然后双击clean清除已有的target,再双击package进行打包。
成功后,左侧可以看到项目的jar包:
03 创建dockerfile文件 在项目的根目录(也就是与pom.xml同级的目录),创建一个dockerfile文件。
根据自己的项目情况填写,此图仅为参考。
04 部署并运行 点击Dockerfile文件编辑界面左上角的三角形符号运行该容器。
先配置运行参数,再运行:
全程没敲一行命令,还是挺不错的。
更多详细用法可自行探索。
1.MYSQL主从简介 1.1 什么是MYSQL主从 MYSQL主从是指,创建两个或以上的相同内容的数据库,而其中一个作为主数据库用于增删改,而另外的作为从数据库用于查操作.这样一是因为一个数据库难以处理高并发的请求,另一个就是防止数据都放在同一个库中而容易出现数据丢失的风险.
1.2 基本原理 在主数据库master实现了修改的事务前,会将这些事务写入日志文件中,当写入操作完成后,master通知储存引擎提交事务.而从数据库slave们会将日志内容拷贝到中继日志中,最后再读出中继日志以完成和主数据库master的数据同步
2. docker上搭建mysql主从 2.1 搭建前的准备 在根目录下的usr/local文件夹中创建software文件夹,进入software后创建以下格式的文件 打开端口的访问,不建议直接关闭防火墙 firewall-cmd --zone=public --add-port=3306/tcp --permanent firewall-cmd --zone=public --add-port=3310/tcp --permanent firewall-cmd --zone=public --add-port=3312/tcp --permanent firewall-cmd --reload 在3306/conf,3310/conf,3312/conf下创建my.cnf配置文件,文件中先写入以下内容 [mysqld] pid-file = /var/run/mysqld/mysqld.pid socket = /var/run/mysqld/mysqld.sock datadir = /var/lib/mysql secure-file-priv= NULL default_authentication_plugin=mysql_native_password # Custom config should go here !includedir /etc/mysql/conf.d/ server_id=200 2.2 配置主服务器master容器 命令行中输入以下代码,密码可以自己更改,别忘记就行 docker run -it \ --name mysql_3306 \ --privileged \ -p 3306:3306 \ -v /usr/local/software/mysql/3306/conf/my.cnf:/etc/mysql/my.cnf \ -v /usr/local/software/mysql/3306/data:/var/lib/mysql \ -v /usr/local/software/mysql/3306/mysql-files:/var/lib/mysql-files \ -e MYSQL_ROOT_PASSWORD=123 \ -d mysql 再输入docker ps -a检查容器是否创建成功,成功效果如下: 进入docker容器运行mysql,没问题即可 2.
题目
. .-.. --- ...- . -.-- --- ..-
解为flag{}的形式
直接使用摩斯解密可得:flag{ILOVEYOU}
文章目录 学习链接前言ffmpeg安装ffmpeg配置环境变量分割视频文件 后台配置WebConfig 前端代码video.js示例安装依赖视频播放组件效果 Vue3-video-play示例安装依赖main.js中使用视频播放组件效果 学习链接 ffmpeg官网
长时长视频java存储及vue播放解决方法
【 攻城略地 】vue3 + video.js播放m3u8视频流格式
Vue3-video-play组件官网
Vue3视频播放器组件Vue3-video-play入门教程
vue-video-player播放m3u8格式的视频
Spring boot视频播放(解决MP4大文件无法播放),整合ffmpeg,用m3u8切片播放。
Java获取MP4视频文件的每一帧图片并保存
mp4视频分片生成m3u8流文件并加密
web播放m3u8文件且进行加密处理
vue中使用vue-video-player,播放m3u8格式的视频及设置请求头
关于H5中的标签的用法总结
JS自定义多媒体Video控制条(控制视频播放、进度、全屏案例)
<video>: 视频嵌入元素 MDN
SpringBoot + Vue 实现视频播放
SpringBoot和Vue集成视频播放组件——基于SpringBoot和Vue的后台管理系统项目系列博客(二十二)
自制视频网站 Vue+SpringBoot全栈 - 演示视频 + github代码地址
ckplayer播放视频gitee代码地址
ckplayer官方文档
ffmpeg 视频ts切片生成m3u8
Spring-Boot实现HTTP大文件断点续传分片下载-大视频分段渐进式播放
springboot+vue播放视频流(无需下载视频,可以拖动进度、倍速播放)
前言 当一个视频文件过大时,不可能一次性的将整个视频的文件流全部写给前端。所以需要用到ffmpeg,将视频按时间分割成ts文件,ts文件比较小,因此浏览器就可以请求这个ts文件,ffmpeg在将视频分割成ts文件时,还会生成一个.m3u8的文件,它相当于与是这些分割的ts文件的一个索引,所以前端只要拿到这个索引文件,并且根据这个索引文件去拿ts文件来做播放。
只是实现了个视频播放的demo,至于还有些问题,没深入,这些就后面再慢慢弄懂吧
都能拿到这个m3u8文件的话,那岂不是所有人都能访问,前端如何和后端做认证或加密什么的清晰度该怎么实现 ffmpeg 安装ffmpeg 下载ffmpeg,并且安装到本机电脑,将ffmpeg的安装位置的bin目录,配置到环境变量中,方便直接调用它的命令
配置环境变量 分割视频文件 在视频文件所在目录,执行如下命令(每60s分割成一个文件)
ffmpeg -i ./jvm.mp4 -c:v h264 -flags +cgop -g 30 -hls_time 60 -hls_list_size 0 -hls_segment_filename index%3d.ts index.
springboot2集成knife4j(swagger3) springboot2集成knife4j(swagger3) 环境说明集成knife4j 第一步:引入依赖第二步:编写配置类第三步:放行相关资源 & 保证启动了knife4j第四步:测试一下 第一小步:编写controller第二小步:启动项目,访问api文档 相关资料 环境说明 springboot:2.6.4knife4j-spring-boot-starter:3.0.3 集成knife4j 第一步:引入依赖 <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> 第二步:编写配置类 提示:可以借助配置文件,进一步改造
import com.fasterxml.classmate.ResolvedType; import com.fasterxml.jackson.databind.introspect.AnnotatedField; import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; import com.github.xiaoymin.knife4j.core.model.MarkdownProperty; import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver; import com.ideaaedi.demo.support.EnumDescriptor; import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.reflect.FieldUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import org.springframework.stereotype.Component; import org.springframework.stereotype.Controller; import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.ModelSpecificationBuilder; import springfox.documentation.builders.PathSelectors; import springfox.
springcloud-gateway集成knife4j(swagger3) springcloud-gateway集成knife4j(swagger3) 环境信息准备工作微服务集成knife4j 第一步:编写Knife4jApiInfoProperties第二步:编写配置类Knife4jConfig第三步:放行相关资源 & 保证启动了knife4j 网关集成knife4j 编写配置类Knife4jGatewayConfig 测试验证相关资料 环境信息 spring-boot:2.6.13spring-cloud-alibaba:2021.0.5.0knife4j-spring-boot-starter:3.0.3 准备工作 各微服务&网关引入依赖
<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>3.0.3</version> </dependency> 微服务集成knife4j 第一步:编写Knife4jApiInfoProperties import com.ideaaedi.springcloud.jd.commonspring.config.Knife4jConfig; import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; /** * api 基础信息配置。更多配置信息项见{@link Knife4jConfig} * * @author <font size = "20" color = "#3CAA3C"><a href="https://gitee.com/JustryDeng">JustryDeng</a></font> <img * src="https://gitee.com/JustryDeng/shared-files/raw/master/JustryDeng/avatar.jpg" /> * @since 2021.0.1.D */ @Data @Component public class Knife4jApiInfoProperties { /** * 要扫描api的base包 */ @Value("${api-info.base-package:com}") private String basePackage; /** * 是否启用登录认证 */ @Value("
一、ST7789v介绍 ST7789v是小尺寸液晶中常用的驱动芯片,作者手里的是网上买的一块2.4寸液晶模组,接口
为SPI接口。
网上能找到这个芯片的micropython驱动,这不是本文的重点。
本文的重点是如何利用这个驱动,并使用字库的方法来显示汉字。
我曾经有一篇文章,介绍如何使用unicode字模库在屏幕上显示汉字,如果你对这个方法还不是很了解,可以看一下我之前这篇文章。使用micropython(ESP8266、ESP32)驱动SES 2.66寸墨水屏显示中文_esp8266驱动墨水屏_f4t0x的博客-CSDN博客
二、st7789v原驱动 这个驱动可以在网上找到,我把源码贴下来。
""" Copyright (c) 2020, 2021 Russ Hughes This file incorporates work covered by the following copyright and permission notice and is licensed under the same terms: The MIT License (MIT) Copyright (c) 2019 Ivan Belokobylskiy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
本文将从,Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ 17 个方面综合对比作为消息队列使用时的差异。 1. 资料文档 Kafka:中,有 kafka 作者自己写的书,网上资料也有一些。
rabbitmq:多,有一些不错的书,网上资料多。
zeromq:少,没有专门写 zeromq 的书,网上的资料多是一些代码的实现和简单介绍。
rocketmq:少,没有专门写 rocketmq 的书,网上的资料良莠不齐,官方文档很简洁,但是对技术细节没有过多的描述。
activemq:多,没有专门写 activemq 的书,网上资料多。
2. 开发语言 Kafka:Scala
rabbitmq:Erlang
zeromq:c
rocketmq:java
activemq:java
3. 支持的协议 Kafka:自己定义的一套...(基于 TCP)
rabbitmq:AMQP
zeromq:TCP、UDP
rocketmq:自己定义的一套...
activemq:OpenWire、STOMP、REST、XMPP、AMQP
4. 消息存储 Kafka:内存、磁盘、数据库。支持大量堆积。
kafka 的最小存储单元是分区,一个 topic 包含多个分区,kafka 创建主题时,这些分区会被分配在多个服务器上,通常一个 broker 一台服务器。分区首领会均匀地分布在不同的服务器上,分区副本也会均匀的分布在不同的服务器上,确保负载均衡和高可用性,当新的 broker 加入集群的时候,部分副本会被移动到新的 broker 上。根据配置文件中的目录清单,kafka 会把新的分区分配给目录清单里分区数最少的目录。默认情况下,分区器使用轮询算法把消息均衡地分布在同一个主题的不同分区中,对于发送时指定了 key 的情况,会根据 key 的 hashcode 取模后的值存到对应的分区中。
rabbitmq:内存、磁盘。支持少量堆积。
rabbitmq 的消息分为持久化的消息和非持久化消息,不管是持久化的消息还是非持久化的消息都可以写入到磁盘。持久化的消息在到达队列时就写入到磁盘,并且如果可以,持久化的消息也会在内存中保存一份备份,这样可以提高一定的性能,当内存吃紧的时候会从内存中清除。非持久化的消息一般只存在于内存中,在内存吃紧的时候会被换入到磁盘中,以节省内存。
引入镜像队列机制,可将重要队列“复制”到集群中的其他 broker 上,保证这些队列的消息不会丢失。配置镜像的队列,都包含一个主节点 master 和多个从节点 slave,如果 master 失效,加入时间最长的 slave 会被提升为新的 master,除发送消息外的所有动作都向 master 发送,然后由 master 将命令执行结果广播给各个 slave,rabbitmq 会让 master 均匀地分布在不同的服务器上,而同一个队列的 slave 也会均匀地分布在不同的服务器上,保证负载均衡和高可用性。
文章目录 前言一、滑动验证破解思路二、案例讲解三、代码实现 前言 有小伙伴们私信反馈说,在web自动化的过程中,经常会被登录的验证码给卡住,不知道如何去通过验证码的验证。今天专门给大家来聊聊验证码的问题,一般的情况下遇到验证码我们可以都可以找开发去帮忙解决,关闭验证码!我们自己有没有办法来处理这些验证码的问题呢?答案当然是有的,常见的验证码一般分为两类,一类是图文验证码,一类是滑块验证码!
关于图文识别的验证码,之前已经出了相关的识别解决方案,今天就不做过多的介绍了,有兴趣的小伙伴可以 领取配套的视频资料 。今天我们主要来聊聊滑动验证码如何去识别破解。
→→→先领资料,再学习←←← 一、滑动验证破解思路 关于滑动验证码破解的思路大体上来讲就是以下两个步骤:
获取滑块滑动的距离
模拟拖动滑块,通过验证。
看起来是很难,实际一点都不简单。 但是获取滑块滑动的距离,大多数小伙伴没有思路,不知道怎么去获取。其实要获取下来也不难,关于这种滑动的验证码,滑块和缺口背景都是分别是一张独立的图片,我们可以把这两张图片,下载下来借助于图像识别的技术,去识别缺口在背景图中的位置,然后减去滑块当前所在位置,就可以得出需要滑动的距离。这个时候很多小伙伴会想图像识别技术我不会啊,不会没有关系,后面会给到大家一个封装好的滑块识别模块,只要你传入滑块和缺口背景图的元素节点就能计算出滑块的缺口位置。
二、案例讲解 话不多说,我们先来看一个案例,这边用到了一个我自己封装的滑动距离识别的模块slideVerfication,有需要的小伙伴可以文末名片处获取。登录案例实现步骤如下:
创建一个driver对象,访问qq登录页面输入账号密码点击登录模拟滑动验证 三、代码实现 import time from selenium import webdriver from slideVerfication import SlideVerificationCode # 1、创建一个driver对象,访问qq登录页面 browser = webdriver.Chrome() browser.get("https://qzone.qq.com/") # 2、输入账号密码 # 2.0 点击切换到登录的iframe browser.switch_to.frame('login_frame') # 2.1 点击账号密码登录 browser.find_element_by_id('switcher_plogin').click() # 2.2定位账号输入框,输入账号 browser.find_element_by_id("u").send_keys("123292678") # 2.3定位密码输入输入密码 browser.find_element_by_id("p").send_keys("PYTHON01") # 3、点击登录 browser.find_element_by_id('login_button').click() time.sleep(3) # 4、模拟滑动验证 # 4.1切换到滑动验证码的iframe中 tcaptcha = browser.find_element_by_id("tcaptcha_iframe") browser.switch_to.frame(tcaptcha) # 4.2 获取滑动相关的元素 # 选择拖动滑块的节点 slide_element = browser.
上一篇描述了在win10下,基于anaconda & pytorch 的深度学习环境的准备搭建过程,下面进行个人数据集的准备,YOLOV5的代码下载测试,训练个人数据集测试识别效果。
一、个人数据集的准备 做深度学习,YOLOV5模型的图像识别,我们需要大量的数据集来进行训练,才能达到准确识别的效果。
制作数据集需要用到 lebelimg 来将我们的数据图片做数据标注生成xml文件。
1.1 libelimg 的安装 (下面是安装过程,可以按步骤进行安装,也可以直接用exe程序 省去安装过程 - 已经上传到我的资源)
首先打开cmd命令行(快捷键:win+R)。进入cmd命令行控制台。输入如下的命令:
pip install labelimg -i https://pypi.tuna.tsinghua.edu.cn/simple 运行如上命令后,系统就会自动下载labelimg相关的依赖。由于这是一个很轻量的工具,所以下载起来很快。
1.2 使用labelimg 准备个人数据集 首先我们需要准备 - 需要打标注的数据集。建议新建一个名为VOC2007的文件夹(通常yolo模型中数据集都以这个为名称,统一不易出错 & 当然你想要个性一点起一个自己名字***也不是不行,在后面的训练中自己可以分清楚就OK),
里面创建一个名为JPEGImages的文件夹存放我们需要打标签的图片文件;再创建一个名为Annotations存放标注的标签文件;最后创建一个名为 predefined_classes.txt 的txt文件来存放所要标注的类别名称。
VOC2007的目录结构为:
├── VOC2007
│├── JPEGImages 存放需要打标签的图片文件
│├── Annotations 存放标注的标签文件
│├── predefined_classes.txt 定义自己要标注的所有类别(在我们定义类别比较多的时候,创建一个这样的txt文件来存放类别)
将要所有训练的数据集图片放到JPEGImages文件夹下,待标注。
(若有多个类别将要定义,将类名输入到predefined_classes.txt文件中,如图:
之后打开刚刚下载的labelimg(也可在python命令行终端输入labelimg打开)
(若直接使用exe程序 ,则直接打开就可以,如图:)
打开后为如下界面:(后面为标注程序,前面终端可显示你的操作记录)
下面介绍图中的我们常用的按钮。
待标注图片数据的路径文件夹,这里输入命令的时候就选定了JPEGImages。(当然这是可以换的)
保存类别标签的路径文件夹,这里我们选定了Annotations文件夹。
常用快捷键如下:
A:切换到上一张图片
D:切换到下一张图片
W:调出标注十字架
del :删除标注框框
Ctrl+u:选择标注的图片文件夹
Ctrl+r:选择标注好的label标签存在的文件夹
开始标注:
先点击open打开单个图片,或者open air直接打开要标注图片所在文件夹
再点击create rectbox ,出现红色十字进行框选标注,框选后需要输入标注框的类名,即我们进行训练的类名。 最后点save ,我们所标注的xml文件就保存在了对应的文件夹。
目录
创建容器并运行
搭建mysql(master)服务器
搭建mysql(slave)从服务器3311
配置主从
创建容器并运行 1.
docker run
-i:以交互模式运行容器
-t:为容器重新分配一个伪输入终端
—name :容器名称
—privileged: 设置容器公开权限(默认为true)
-p :映射端口 linux端口: 容器内置端口(mysql默认端口为3306)
-v : linux挂载文件夹/文件和容器内路径的映射
-e: 容器的环境变量(设置mysql默认用户名&密码)
-d: 后台运行容器,并返回容器ID
2. 进入容器
3.容器中运行MySQL客户端
如果登录成功证明docker安装MySQL成功
4.退出容器、
输入:exit
5.开放指定端口 firewall-cmd —zone=public —add-port=端口号/tcp —permanent
—zone: public 公开端口
—add-port: 端口号/协议名称
—permanent: 永久开放
6. 重新加载防火墙
7. 查看开放的端口号
8.navicat测试连接
1.检查binlog是否开启 进入主mysql容器,输入命令: show variables LIKE ‘log_%’
ON: 表示已开启
2.查看当前mysql容器中的binlog日志文件
切换目录到 / var/lib/mysql,查看日志文件
3.查看当前mysql数据库binlog情况
登录mysql客户端: mysql -uroot -p123
使用命令: show master status;
一、linux创建配置文件、文件夹 在/usr/local/先创建software文件夹,再在software下创建mysql文件夹,文件结构如下
二、拷贝my.cnf文件到conf文件夹下 三、查询拉取mysql镜像 docker search mysql
四、拉取mysql镜像到本地(linux) docker pull mysql 结果:拉取的是最新版本
五、查询镜像检查是否已下载到本地 docker image ls
六、创建运行mysql容器(master) 创建容器并运行 i:以交互模式运行容器 t:为容器重新分配一个伪输入终端
name :容器名称
privileged: 设置容器公开权限(默认为true)p :映射端口 linux端口: 容器内置端口(mysql默认端口为3306)v : linux挂载文件夹/文件和容器内路径的映射 e: 容器的环境变量(设置mysql默认用户名&密码)
d: 后台运行容器,并返回容器ID
注意路径要和自己实际情况保持一致
docker run -it \
--name mysql_3306 \
--privileged \
-p 3306:3306 \
-v /usr/local/software/mysql/3306/conf/my.cnf:/etc/mysql/my.cnf \
-v /usr/local/software/mysql/3306/data:/var/lib/mysql \
-v /usr/local/software/mysql/3306/mysql-files:/var/lib/mysql-files \
-e MYSQL_ROOT_PASSWORD=sxq123456 \
-d mysql
七、进入容器 docker exec -it:以交互模式运行容器 ,为容器重新分配一个伪输入终端。bash: bash(GNU Bourne-Again Shell)是最常用的一种shell(运行在终端的互动程序)。 docker exec -it mysql_3306 bash
目录
一、树结构存在的原因
二、树的示意图
三、树的种类
四、二叉树的代码实现
4.1、节点类
4.2、有序二叉树的遍历
4.3、构建有序二叉树
4.4、递归实现二叉树
4.5、递归遍历二叉树
4.6、有序二叉树的删除
4.6.1、叶子结点的删除
4.6.2、删除只有一个子树的节点
4.6.3、删除有两个子树的节点
4.6.4、节点删除代码实现
一、树结构存在的原因 1、数组存储方式分析
优点:通过下表方式访问元素,速度快。对于有序数组没还可以使用二分查找提高检索速度。
缺点:如果要检索某一个具体值,效率比较低下
2、链式存储方式分析
优点:在一定程度上对数组存储方式进行优化(比如插入一个节点,只需要将插入节点,链接到链表当中可删除的效率也很好)。
缺点:在进行检索时,效率仍然比较低,比如(检索某个数值,需要从头结点开始遍历)
3、树存储方式分析
能提高数据存储,读取的效率,比如利用二叉排序树,既可以保证数据的检索速度。同时也可以保证数据的插入,删除,修改的速度。
二、树的示意图 三、树的种类 1.树有很多种,每个节点最多只能有两个子节点的一种形式称为二叉树
2.二叉树的子节点分为左节点和右节点
3.如果二叉树的所有叶子节点都在最后一层并且总结点数 = 2^n-1,(n为层数),则我们称为满二叉数。
4.如果二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续,我们称为完全二叉树。
四、二叉树的代码实现 4.1、节点类 public class TreeNode { private TreeNode leftTreeNode; private TreeNode rightTreeNode; private Integer value; public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public TreeNode(Integer value){ this.value = value; } public TreeNode getLeftTreeNode() { return leftTreeNode; } public void setLeftTreeNode(TreeNode leftTreeNode) { this.
报错 Could not open device at /dev/ipmi0 or /dev/ipmi/0 or /dev/ipmidev/0: No such file or directory
解决 输入modprobe ipmi_si
modprobe ipmi_si 当添加ipmi_si时,提示:
modprobe: ERROR: could not insert ‘ipmi_si’: No such device
说明机器上没有IPMI设备。
1.导入EasyExcel,maven依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.10</version> </dependency> 2.添加EasyExcelUtil工具类 package org.springblade.modules.system.EuipmentExcelImplement; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.write.metadata.WriteSheet; import lombok.extern.slf4j.Slf4j; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; @Slf4j public class EasyExcelUtil { /** * 创建即将导出的sheet页(sheet页中含有带下拉框的列) * @param head 导出的表头信息和配置 * @param sheetNo sheet索引 * @param sheetName sheet名称 * @param <T> 泛型 * @return sheet页 */ public static <T> WriteSheet writeSelectedSheet(Class<T> head, Integer sheetNo, String sheetName) { Map<Integer, ExcelSelectedResolve> selectedMap = resolveSelectedAnnotation(head); return EasyExcel.writerSheet(sheetNo, sheetName) .
计算机,右键-管理
管理–服务–cpolar service,停止服务
第十三章:软件项目管理 一、软件项目管理总述 1.管理 管理是通过计划、组织和控制等一系列活动,合理地配置和使用各种资源,以达到既定目标的过程。 2.软件项目管理 软件项目管理先于任何技术活动之前开始,并且贯穿于软件的整个生命周期之中。软件项目管理过程从一组项目计划活动开始,而制定计划的基础是工作量估算和完成期限估算。 二、估算软件规模 1.代码行技术 (1)定义
代码行技术依据以往开发类似产品的经验和历史数据,估计实现一个功能所需要的源程序行数。是一种比较简单的定量估算软件估摸的方法。
(2)方法
①把实现每个功能的源程序行数累加起来,可得到实现整个软件所需要的源程序行数。
②估计程序的最小规模(a)、最大规模(b)和最可能的规模(m),分别算出这3种规模的平均值后,再用下式计算程序规模的估计值:(13.1)
③程序小时用的单位是代码行数(LOC);程序大时用的单位是千行代码数(KLOC)。
(3)优点
①代码是所有软件开发项目都有的“产品”,而且很容易计算代码行数。
②有以往开发类似产品的历史数据可参考时,估计出的数值比较准确。
(4)缺点
①源程序仅是软件配置的一个成分,用它的规模代表整个软件的规模不太合理。
②用不同语言实现同一个软件所需要的代码行数并不相同。
③不适用于非过程语言。
(13.1)
2.功能点技术 (1)定义
功能点技术依据对软件信息域特性和软件复杂性的评估结果,估算软件规模。用功能点(FP)为单位度量软件规模。是为了克服代码行技术的缺点,提出来的新技术。
(2)信息域特性
①输入项数(Inp):用户向软件输入的项数,这些输入给软件提供面向应用的数据。
②输出项数(Out):软件向用户输出的项数,它们向用户提供面向应用的信息。
③查询数(Inq):一次联机输入,它导致软件以联机输出方式产生某种即时响应。
④主文件数(Maf):逻辑主文件(数据的一个逻辑组合)的数目。
⑤外部接口数(Inf):机器可读的全部接口数量,用这些接口把信息传送给另一个系统。 三、工作量估算 软件估算模型使用由经验导出的公式来预测软件开发工作量,工作量是软件规模的函数,工作量的单位通常是人月(pm)。没有一个估算模型可以适用于所有类型的软件和开发环境。
1.静态单变量模型 2.动态多变量模型 3.COCOMO2模型 四、进度计划 1.相关概念 (1)任务集合
一个有效的软件过程应该定义一个适用于当前项目的任务集合。一个任务集合包括一组软件工程工作任务、里程碑和可交付的产品。为一个项目所定义的任务集合,必须包括为获得高质量的软件产品而应该完成的所有任务,但是同时又不能让项目组承担不必要的工作。
(2)项目管理者的工作
①目标
定义全部项目任务,识别出关键任务,跟踪关键任务的进展状况,保证及时发现拖延进度的情况。
②方法
管理者必须制定一个足够详细的进度表,以便监督项目进度并控制整个项目。
(3)进度安排
①定义
软件项目的进度安排通过把工作量分配给特定的软件工程任务并规定完成各项任务的起止日期,从而将估算出的项目工作量分布于计划好的项目持续期内。进度计划将随着时间的流逝而不断演化。
②流程
a.在项目计划的早期,制定一个宏观的进度安排表,标识出主要的软件工程活动和这些活动影响到的产品功能。
b.随着项目的进展,把宏观进度表中的每个条目都精化成一个详细进度表,标识出完成一个活动所必须实现的一组特定任务,并安排好实现这些任务的进度。 2.估算开发时间 P312 3.Gantt图 (1)例子
假设有一座陈旧的矩形木板房需要重新油漆。这项工作必须分3步完成:首先刮掉旧漆,然后刷上新漆,最后清除溅在窗户上的油漆。假设一共分配了15名工人去完成这项工作,然而工具却很有限:只有5把刮旧漆用的刮板,5把刷漆用的刷子,5把清除溅在窗户上的油漆用的小刮刀。怎样安排才能使工作进行得更有效呢?
(2)优点
①很形象地描绘任务分解情况,以及每个子任务(作业)的开始时间和结束时间。
②容易掌握、容易绘制。
(3)缺点
①不能显式地描绘各项作业彼此间的依赖关系。
②进度计划的关键部分不明确,难于判定哪些部分应当是主攻和主控的对象。
③计划中有潜力的部分及潜力的大小不明确,往往造成潜力的浪费。
图13.1 旧木板房刷漆工程的Gantt图
4.工程网络 (1)定义
工程网络可以描绘任务分解情况以及每项作业的开始时间和结束时间,它还显式地描绘各个作业彼此间的依赖关系。
(2)表示
Python实现爬虫 一、介绍 网络爬虫是一种自动获取互联网信息的程序,可以用于抓取各种网站上的数据。本文将介绍如何使用Python编写一个简单的爬虫,来抓取文章。
二、环境准备 在开始编写爬虫之前,需要安装Python和相关的第三方库。请确保已经安装了Python解释器,并使用以下命令安装所需的库:
pip install requests pip install beautifulsoup4 其中,requests库用于发送HTTP请求,beautifulsoup4库用于解析HTML文档。
三、发送HTTP请求 首先,我们需要发送HTTP请求来获取网页内容。使用requests库可以很方便地实现这一步骤。下面是发送GET请求的代码示例:
import requests url = 'https://www.csdn.net/' response = requests.get(url) html = response.text 在上述代码中,我们使用get()方法发送了一个GET请求,并将返回的响应保存在response变量中。然后,通过response对象的text属性获取到网页的HTML内容。
四、解析HTML文档 接下来,我们需要使用beautifulsoup4库来解析HTML文档,从中提取出我们需要的信息。下面是一个简单的示例代码,用于解析网页的标题和链接:
from bs4 import BeautifulSoup soup = BeautifulSoup(html, 'html.parser') articles = soup.find_all('div', class_='title') for article in articles: title = article.a.text link = article.a['href'] print(title, link) 在上述代码中,我们首先将HTML文档传递给BeautifulSoup类进行解析。然后,使用find_all()方法找到所有class属性为"title"的div标签。接着,通过遍历这些div标签,我们可以获取到每篇文章的标题和链接。
五、存储数据 最后,我们可以将获取到的文章标题和链接存储到文件中,或者进行其他处理。以下是一个简单的示例代码,将标题和链接写入到CSV文件中:
import csv with open('articles.csv', 'w', newline='', encoding='utf-8') as csvfile: writer = csv.writer(csvfile) writer.writerow(['标题', '链接']) for article in articles: title = article.
1.组件 组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用
Vue 中注册组件:
// 定义名为 todo-item 的新组件 Vue.component('todo-item', { template: '<li>这是个待办项</li>' }) var app = new Vue(...) Vue的核心库只关注图层.响应式数据绑定和组件化开发是其两大特点.
组件化开发指的是vue.js通过组件,把一个单页应用中的各种模块拆分到一个个单独的组件(component)中,我们只要先在父级组件中写好各种组件标签,并且在组件标签中写好要传入组件的参数,然后在写好各种组件的实现,整个应用就可以完成了
2.vscode搭建vue项目 **2.1安装配置** 安装vue插件vetur,实现支持vue文件的代码高亮 推荐插件列表  安装node.js 下载地址:[https://nodejs.org/en/download/](https://nodejs.org/en/download/) 下载完成后默认安装,安装完成后打开cmd 输入下面的命令查看是否成功安装 node -v npm -v 2.2 使用脚手架安装项目
用管理员进入新建项目文件夹
配置基本vue环境(vue-cli@2.9.4版本开始,它会要求你安装额外的东西,导致vue init webpack Travel初始化项目的时候会失败)
npm install -g vue-cli@2.9.3 //卸载vue-cli,如果不小心装错 npm uninstall -g vue-cli 进入文件夹cmd或者
进入vscode
点击Terminal菜单,切换到对应的准备存放代码的目录
vue init webpack vue_project 最后输入npm run dev运行项目
3.目录解析
build :项目构建(webpack)相关代码
config :配置目录,包括端口号等。我们初学可以使用默认的
node_modules :npm 加载的项目依赖模块
深拷贝和浅拷贝在Python中是非常重要的存在,但很多人对它们了解的并不是很清楚,本文为大家详细讲解一下深浅拷贝的概念、使用场景以及注意事项,希望能够给你带来帮助。
1、Python深浅拷贝概念
在Python中,当进行赋值操作时,实际上是将一个对象的应用赋给了一个变量,因此这两个变量指向的是同一个对象。如果我们需要复制一个对象,那么就需要使用拷贝操作。
浅复制是指新建一个对象,然后将原始对象的引用复制给新对象。由于新对象与原始对象同一内存地址,因此一个对象的值被修改后,另一个对象的值也会受到影响。浅拷贝只复制对象的一层内容。
递归复制原始对象及其子对象的所有内容,从而创建一个新的对象,这就是深度复制。由于新对象与原始对象并无共享内存地址,故而二者完全独立,因此更改其中一个对象的值并不会影响另一个对象的值。
2、Python深浅拷贝使用场景
浅拷贝适合于对象层次结构较浅的情况,比如列表、元组、字典等简单对象的复制。如果对象的元素全部为不可变类型,则可以使用浅拷贝来复制该对象。
如果对象层次结构比较复杂,例如嵌套列表的列表或嵌套字典的字典,那么深拷贝就是一个合适的选择。如果一个对象的元素包含可变对象,那么在需要进行拷贝时必须使用深拷贝。
3、Python深浅拷贝注意事项
对于不可变对象,浅拷贝和深拷贝都是相同的。
浅拷贝只会复制可变对象的一层内容,而不会递归复制可变对象包含的子对象。如果需要递归复制子对象,必须使用深拷贝。
当一个对象包含循环引用时,尝试进行深复制可能会导致无限递归,从而导致程序崩溃。因此,在使用深拷贝时,必须小心处理包含循环引用的对象。
在使用深拷贝时,如果对象的层次结构比较复杂,可能会导致性能问题,因此必须小心使用深拷贝。
在社交媒体时代,拥有忠实的粉丝群体对个人和企业来说都非常重要。本文将分享一些有效的方法,帮助您获得铁粉,并建立一个忠诚的粉丝基础。
1、提供有价值的内容: 铁粉们会因为您提供的有价值的内容而对您产生兴趣。确保您的文章、视频或其他形式的内容具有深度、独特性和实用性。
2、与粉丝互动: 与粉丝进行互动是建立忠实粉丝群体的关键。回复他们的评论、私信或电子邮件,并尽量参与到他们的讨论中去。
3、定期更新: 保持定期更新您的内容,让粉丝们知道他们可以期待您的新作品。建立一个固定的发布计划,并坚持下去。
4、利用社交媒体: 在各种社交媒体平台上建立您的存在,并与粉丝进行互动。了解您的目标受众使用的平台,并确保您的内容适应不同的社交媒体环境。
5、提供独家福利: 为您的粉丝提供独家的优惠、折扣或其他特殊待遇,以表达对他们的感谢。这样可以增加他们的忠诚度,并激励他们继续支持您。
6、参与社区: 加入相关的社区,与其他人分享您的知识和经验。这样可以扩大您的影响力,并吸引更多的粉丝。
7、建立个人品牌: 建立一个独特的个人品牌,使您在人们心中留下深刻的印象。通过一致的形象和声音,让人们对您产生认同感。
总结:获得铁粉是一个长期的过程,需要持续的努力和耐心。通过提供有价值的内容、与粉丝互动、定期更新、利用社交媒体、提供独家福利、参与社区和建立个人品牌,您可以逐渐建立一个忠诚的粉丝基础。
优质博客: 单体项目偶遇并发漏洞!短短一夜时间竟让老板蒸发197.83元! - 掘金
什么是乐观锁,什么是悲观锁? 一、并发控制 当程序中可能出现并发的情况时,就需要保证在并发情况下数据的准确性,以此确保当前用户和其他用户一起操作时,所得到的结果和他单独操作时的结果是一样的。这就叫做并发控制。并发控制的目的是保证一个用户的工作不会对另一个用户的工作产生不合理的影响。
没有做好并发控制,就可能导致脏读、幻读和不可重复读等问题。
常说的并发控制,一般都和数据库管理系统(DBMS)有关。在 DBMS 中并发控制的任务,是确保多个事务同时增删改查同一数据时,不破坏事务的隔离性、一致性和数据库的统一性。
实现并发控制的主要手段分为乐观并发控制和悲观并发控制两种。
无论是悲观锁还是乐观锁,都是人们定义出来的概念,可以认为是一种思想。其实不仅仅是关系型数据库系统中有乐观锁和悲观锁的概念,像 hibernate、tair、memcache 等都有类似的概念。所以,不应该拿乐观锁、悲观锁和其他的数据库锁等进行对比。乐观锁比较适用于读多写少的情况(多读场景),悲观锁比较适用于写多读少的情况(多写场景)。
二、悲观锁(Pessimistic Lock) 1️⃣理解
当要对数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。这种借助数据库锁机制,在修改数据之前先锁定,再修改的方式被称之为悲观并发控制【Pessimistic Concurrency Control,缩写“PCC”,又名“悲观锁”】。
悲观锁,具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度。因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。
之所以叫做悲观锁,是因为这是一种对数据的修改持有悲观态度的并发控制方式。总是假设最坏的情况,每次读取数据的时候都默认其他线程会更改数据,因此需要进行加锁操作,当其他线程想要访问数据时,都需要阻塞挂起。悲观锁的实现:
传统的关系型数据库使用这种锁机制,比如行锁、表锁、读锁、写锁等,都是在操作之前先上锁。Java 里面的同步 synchronized 关键字的实现。 2️⃣悲观锁主要分为共享锁和排他锁:
共享锁【shared locks】又称为读锁,简称 S 锁。顾名思义,共享锁就是多个事务对于同一数据可以共享一把锁,都能访问到数据,但是只能读不能修改。排他锁【exclusive locks】又称为写锁,简称 X 锁。顾名思义,排他锁就是不能与其他锁并存,如果一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁,包括共享锁和排他锁。获取排他锁的事务可以对数据行读取和修改。 3️⃣说明
悲观并发控制实际上是“先取锁再访问”的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理加锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会。另外还会降低并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。
三、乐观锁(Optimistic Locking) 1️⃣理解
乐观锁是相对悲观锁而言的,乐观锁假设数据一般情况不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。乐观锁适用于读多写少的场景,这样可以提高程序的吞吐量。
乐观锁采取了更加宽松的加锁机制。也是为了避免数据库幻读、业务处理时间过长等原因引起数据处理错误的一种机制,但乐观锁不会刻意使用数据库本身的锁机制,而是依据数据本身来保证数据的正确性。乐观锁的实现:
CAS 实现:Java 中java.util.concurrent.atomic包下面的原子变量使用了乐观锁的一种 CAS 实现方式。版本号控制:一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会 +1。当线程 A 要更新数据时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。 2️⃣说明
乐观并发控制相信事务之间的数据竞争(data race)的概率是比较小的,因此尽可能直接做下去,直到提交的时候才去锁定,所以不会产生任何锁和死锁。
四、具体实现 1️⃣悲观锁实现方式
悲观锁的实现,往往依靠数据库提供的锁机制。在数据库中,悲观锁的流程如下:
在对记录进行修改前,先尝试为该记录加上排他锁(exclusive locks)。如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。具体响应方式由开发者根据实际需要决定。如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。期间如果有其他对该记录做修改或加排他锁的操作,都会等待解锁或直接抛出异常。 以 MySql Innodb 引擎举例,说明 SQL 中悲观锁的应用
文章目录 前言 一、打开和关闭文件(open和close) 1.打开文件 2.关闭文件 mode的方式 几种读取文件的函数 写入文件的函数 二、with…open…as操作文件 1、with…open…as与open......close的区别 总结 前言 本篇文章讲解,平时读写文件的基本用法 一、打开和关闭文件(open和close) 语法:
open(file, mode, encoding=None) 讲解字段含义: file:文件(其实是一个具体文件的路径) 例如: 在D盘我创建了一个名为:qhj.txt的文件,那么file就应该是:D:\study\qhj.txt mode:打开文件的方式(以什么样的方式打开这个文件) encoding:编码(以什么样的方式来编码) 1.打开文件 字段讲解:
r"D:\study\qhj.txt" :也就是file
"r" :也就是mode
encoding="utf-8" :也就是encoding=None,只不过这个传了具体值"utf-8",所以不再是默认的None
注意:其实上面这种方式是一种省略的方式写法,可能对于初学者有点疑惑,为什么r"D:\study\qhj.txt"的前面,"r"的前面没有一个参数,而"utf-8"前面就有encoding呢?
其实我们还原最基本的(标准的)写法就明白了。
2.关闭文件 语法:file.close() #注意:这里的file是一个对象,使用对象调出函数,来操作关闭。 举例: mode的方式: 以读为主 r 以只读方式打开文件。指针将会放在文件的开头(这是默认模式); read 只能读不能写,文件不存在的时候会报错 rb 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。 r+ 打开一个文件用于读写。文件指针将会放在文件的开头。 读写模式 文件不存在的时候会报错 可读可写,但是写的有问题(在最前方写,因为指针在0处) rb+ 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 以写为主 w 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。(也就是写入的内容把原有的内容的覆盖了); write 文件不存在的话,给创建,不能读,写之前会清空原来的文件内容 wb 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 w+ 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件; 写读模式 文件不存在的时候给创建 清空文件内容,然后在写 wb+ 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 以追加为主 a 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 追加模式 不会清空原来的内容 追加写,但是不能读 ab 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 追加模式 文件不存在的时候给创建 可读可写 ,追加写,但是读不到内容(因为指针在末尾,所以读不到) ab+ 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 注意:这些字母可能有些不好记,那么可以还原成英语单词来记忆: r 的单词意思是:read w 的单词意思是:write a 的单词意思是:append b 的单词意思是:binary(二进制) 几种读取文章的函数: readlines() :读取所有行,以列表的形式返回读取内容,列表的每一个元素对应文件的一行 readline():按行读取文件的内容,换行符号 ‘\n’ read([size]):默认读取全部文件内容,如果有size参数,则读取前size个字节数 举例: (1)读取文件的全部数据
回收策略:引用计数法和标记清除法
标记清除法的缺点是
js是单线程,遇到垃圾回收机制就会全停顿,所以浏览器做了优化,实现多线程并行回收,但是依然阻塞js执行,所以又诞生了增量标记,分段执行垃圾回收,交叉执行
内容来自思学堂:
TCP三次握手:确保双方都在线上
TCP四次握手:处理客户端要断开连接的需求
输入url,解析url信息—>判断强缓存还是协商缓存—>dns域名解析—>TCP三次握手建立连接—>客户端发送http请求,如果是https则涉及加解密流程—>服务器处理请求并返回http资源—>TCP四次握手断开连接—>浏览器拿到资源之后渲染页面,涉及回流和重绘,同时加载js的时候涉及js执行机制
推荐信模版(英文)计算机专业 ✅ 内容已校对 + 润色
©️ 文章来源:https://blog.csdn.net/IYXUAN,原创内容,转载请注明!
推荐信(一) January 4, 2023
Dear Admissions Committee,
As Mr. Jixiang Ding’s teacher, I am pleased to have this opportunity to warmly recommend him for admission to your prestigious university.
I have known Jixiang for over two years, he uniquely stands out among thousands of students I have engaged with. The first time I met him was when he took my course “Discrete Mathematics” in his second year.
win10下 基于Anaconda、pytorch的YOLOV5深度学习环境搭建 环境配置顺序:显卡驱动 - CUDA - cudnn - Anaconda - pytorch - pychorm
按这个顺序配置可以避免很多莫名其妙的错误出现。另外不用单独安装python,使用Anaconda里的python环境。
目录
win10下 基于Anaconda、pytorch的YOLOV5深度学习环境搭建
一、要根据自己的显卡型号安装对应驱动(一般都有装好的驱动)
二、安装CUDA & cudnn
三、安装Anaconda
四、安装Pytorch环境
五、安装pycharm (验证CUDA和cudnn版本)
一、要根据自己的显卡型号安装对应驱动(一般都有装好的驱动) 这里附上NVIDA官方驱动下载地址:官方驱动 | NVIDIA
根据自己电脑配置选择相应显卡驱动下载安装
安装(更新)好了显卡驱动以后。我们按下win+R组合键,打开cmd命令窗口。输入如下的命令。
nvidia-smi 得到如下图的信息图,可以看到驱动的版本是528.24;最高支持的CUDA版本是12.0版本。
得到显卡的最高支持的CUDA版本,我们就可以根据这个信息来安装环境了。
二、安装CUDA & cudnn 1, CUDA下载地址:CUDA Toolkit 12.2 Downloads | NVIDIA Developer
这是最新版本的CUDA,我们需要根据上面查到的信息安装与自己电脑显卡对应版本的CUDA(下载旧版本的CUDA可以点击下面箭头的网址)。
按照以下所选进行下载cuda安装:
2,cudnn下载安装(选择对应CUDA版本的),下载地址:Log in | NVIDIA DeveloperLog in | NVIDIA DeveloperLog in | NVIDIA Developer
安装完成后便可以配置我们进行深度学习需要的环境了(关于CUDA和cudnn,网上的安装教程很全面,我就不在赘述了),下面配置深度学习环境。
三、安装Anaconda 官方下载网址:Free Download | Anaconda
现在最新版本的anaconda支持python3.10。(若需要下载早期版本,可以打开:网址)
双击下载好的anaconda安装包,just me是说只供当前用户使用。all user 是供使用这台电脑的所有用户使用,是权限问题。点击just me。
完成一篇如何获得铁粉,或者相关的文章且质量分达到80分以上即可
一 什么是铁粉? 顾名思义,就是你的铁杆粉丝,但是这个只是过通俗的解释,那么在CSDN规则中,什么是铁粉呢?官方给了一系列解释 “为了帮助博主解决上面提到的问题和困惑, CSDN 设计了 【铁粉】 这个功能(当前铁粉功能已上线,在博客个人主页即可看到,博主可根据自己的需求设置是否可见,如下图), 简单地说,就是在过去 N 个月内,一个博主的粉丝有多少是有一定水平的,并且和博主有高质量互动的。 ”
所以看的出来,铁粉不是发发博文,社区灌灌水,有人关注就会来的,是需要有高质量互动的,什么是高质量互动,那肯定就是技术讨论问题,技术观点等等。那么如何快速积累 铁粉呢?其实博主本人也是刚刚入道,有一些见解,如有偏差,请大家不要见笑,咱们评论区论道即可。
二 如何快速积累铁粉 1、问答互动 真的,说实话,我这点铁粉,基本上都是通过CSDN问答 然后帮问主解决各种问题中,在私信中各种沟通而得来的,我感觉也是最直接最高效的方式吧。问答的过程中本来就会有交互,特别是你的回答在问主有兴趣的时候一般都会主动找你私聊,那么 高质量不就是这么来的吗?
最近刚刚才开始搞问答,但是也是有一定收获的哈。
问答交互
2、高质量且有心机的博文 这个怎么解释呢,其实在很早之前 16年,我就自己建立了一个个人博客站,然后里面都是我学习和工作中的技术心得,其中有一篇文章交互是最多的,就是我当时用js + Pyhton 做的一个 在线图片压缩 + 裁剪 + 水印的一个 插件, 博文中讲解了核心代码,但是完整代码由于结构文件太多,并没有完全贴到博文中,只是在博文最后提示读者如果有兴趣,加我QQ好友,请求好友时备注:xxxx博文中看到的,需求 插件完整代码。
其实当时只是没有把完整的代码放到博文中,但是反而因为这种方式增加了很多相同领域技术的朋友。
这种方式放在吸引铁粉中我觉得也是依然有效的。
3、热门话题积极参与 除了CSDN官方举办的各类热门活动,如果有时间,条件允许的情况下,我还是非常建议大家积极参与的。
另外就是 CSDN APP上的一些热门话题了。不管是社区话题还是动态,我们选择热门话题,同样内容也会得到流量扶持以及粉丝热门话题的讨论,从中也转化出一定的铁粉,比如我就是因为在CSDN参加活动,不仅结交了各类网友,还从CSDN与AWS联合举办的活动中脱颖而出,获得了一些激励,并且活动方邀请我参加 AWS 中国区 Builder。(2022年7月正式加入 AWS Community Builders)
4、技术系列性的定更 这个怎么说呢,就是比如你要写一个go的技术系列博文,从入门,到框架使用,到某些场景的应用,再到实战。这样会吸引大量粉丝,并且如果粉丝有疑问也会跟你私信或评论交互,这样同样能够稳定涨铁粉。
三 整体总结 总而言之,要怎么积累铁粉呢?
如果你急于求成,那么短期内你一定要花大量的时间来做上述说的那么事情,问答、博文、系列博文、热门话题、动态更新等等。但是如果你过了一段时间全部停了,那么铁粉也是会掉的。
如果你稳定发挥,每周更新几个博文、每天回答几个问题、每天发发热门动态、偶尔参加一下官方的各类活动 等等,不管是粉丝,还是铁粉都会稳定增长的。
加油吧!!!!
作者:Carlo
一、支持的主流数据库类型 1、主流数据库介绍 数据库名称版本不支持的数据集类型需要配置 客户端支持工作空间支持集群模式SQLPlus2008/2012/2016/2018(仅 Windows 平台支持)视频、复合点、复合线、复合面、复合文本数据集是是是OraclePlus9i/10g/11g/12c/19c/20c复合点、复合线、复合面、复合文本数据集是是是OracleSpatial9i/10g/11g三维点、三维线、三维面、CAD、网络、三维网络、路由、模型、EPS点、EPS线、EPS面、EPS文本、复合点、复合线、复合面、复合文本数据集是否是MySQL5.6.16及以上版本(仅64位版本支持)复合点、复合线、复合面、复合文本数据集否是否PostgreSQL8.3及以上版本无否是是PostGIS2.2.3(9.6) 以上版本复合点、复合线、复合面、复合文本数据集否是是DMPlus7/8复合点、复合线、复合面、复合文本数据集是是是MongoDB2.x/3.x/4.x栅格、影像、镶嵌数据集否是是UDBX*无*否否Kingbase6/7/8(仅 Windows 平台支持)复合点、复合线、复合面、复合文本数据集是否是GaussDB 200200.6.5复合点、复合线、复合面、复合文本数据集否否是 2、数据库推荐 数据库名称应用场景优点缺点推荐指数PostGIS大体量空间数据管理、适应于大规模生产环境空间对象存储标签公开,支持多平台对接,空间函数支持下沉、支持高并发、读写性能高、支持集群需安装PostgreSQL引擎的空间数据扩展⭐⭐⭐⭐⭐PostgreSQL大体量空间数据管理、对写入性能要求一般超图空间对象存储标签、易于管理、并发性能一般、支持集群不支持其他平台对接⭐⭐⭐⭐OracleSpatial中等体量空间数据管理、对写入性能要求一般空间对象存储标准公开、支持多平台对接、并发性能一般、支持集群购买成本高、不支持三维数据,栅格数据,参数化对象等⭐⭐⭐⭐OraclePlus中等体量空间数据管理、对写入性能要求一般超图空间对象存储标签、易于安全管理、支持集群购买成本高、不支持其他平台对接⭐⭐⭐⭐UDBX(SQLite)中等体量空间数据管理,适用于试验演示环境易用性,轻量级,迁移便捷,读写性能高不支持并发场景、不支持集群⭐⭐⭐MySQL中等体量空间数据管理,适用于试验演示环境易用性,不需安装客户端读写性能一般,不支持集群⭐⭐⭐HighGo基于PostgreSQL、强于它千万级事务处理能力多种数据库开发接口与框架、高可用、安全、高效多版本、多应用场景兼容性好、生态丰富、安全可控、资源手册丰富、读写性能高项目应用较少⭐⭐⭐⭐⭐Kingbase基于PostgreSQL部署简单、快速数据迁移系统可用性高达99.99%多CPU并行处理、高并发、安全四级、上下兼容扩展性强、兼容性好、操作简便网络资源少、读写性能一般⭐⭐⭐⭐DMPlus完全自主研发读写分离、故障自动切换行列融合、高安全等级支持多种云基础设施、硬件平台广泛的SQL语法兼容适配多样、兼容性好、操作简便、安全可控、项目应用多网络资源少、读写性能一般⭐⭐⭐⭐ 注 :针对二维瓦片、三维瓦片的管理推荐使用 MongoDB 数据库
二、SuperMap SDX+ 的系统表说明 SuperMap SDX+是SuperMap GIS的空间数据库引擎,是SuperMap GIS软件的重要组成部分,它采用先进的空间数据库存储技术、索引技术和查询技术,具有"空间-属性数据一体化"、"矢量-栅格数据一体化"和"空间信息-业务信息一体化"的集成式空间数据库管理能力,是GIS大型工程应用的理想选择。
经过实际应用和测试表明,SuperMap SDX+具有以下三项特色:
1)安装使用简便,充分结合数据库技术;
2)高性能管理和访问海量空间数据;
3)完善的数据模型,满足各种大型GIS应用的需求。
SuperMap SDX+ 共有20个系统表,下图为一些重要的系统表结构:
下面是对部分系统表的详细描述:
1、SmRegister—矢量数据集注册信息表 SmRegister表用来集中管理矢量数据集的信息,每新建一个矢量数据集,会在此表中新增加一条记录(带子数据集的矢量数据集,如Network或Tin类型的数据集,会在SmRegister表中添加两条记录),同样删除数据集时会将相应的记录从该表中移除。
字段名称字段类型描述SmDatasetIDINTEGER数据集的唯一编号SmDatasetNameCHARACTER VARYING(64)数据集的名称(别名)SmTableNameCHARACTER VARYING(64)数据集的表名SmIndexTableNameVARCHAR(64)索引表名SmSubTableNameVARCHAR(64)子数据集的表名SmIsSubCHAR(1)标明数据集是否为子数据集SmDatasetTypeINTEGER数据集的类型SmRecordCountINTEGER数据集中记录的数目SmIndexLevelSHORT数据集空间索引的LevelSmLeftDOUBLE数据集的四至SmTopDOUBLE数据集的四至SmRightDOUBLE数据集的四至SmBottomDOUBLE数据集的四至SmIndexTypeDOUBLE数据集空间索引的类型SmIndexLeftDOUBLE索引范围的四至SmIndexTopDOUBLE索引范围的四至SmIndexRightDOUBLE索引范围的四至SmIndexBottomDOUBLE索引范围的四至SmMinZDOUBLE数据集的最小高程值SmMaxZDOUBLE数据集的最大高程值SmLTUserIDINTEGER用于长事务环境,标识长事务用户特定版本SmDtVersionINTEGER标识数据集被修改的版本SmOptionINTEGER数据集的选项信息,如是否压缩存储等SmStateINTEGER并发编辑锁的状态SmEncTypeINTEGER数据集编码类型SmToleranceFuzzyDOUBLE拓扑容限信息SmToleranceDangleDOUBLE拓扑容限信息SmToleranceNodeSnapDOUBLE拓扑容限信息SmToleranceSmallPolygonDOUBLE拓扑容限信息SmToleranceGrainDOUBLE拓扑容限信息SmMaxGeometrySizeINTEGER数据集中最大几何对象的字节数SmOnceFetchCountINTEGER优化参数:一次从服务器中取回的记录数SmOptimizeCountINTEGER优化参数:用于全幅显示优化的最大记录数SmOptimizeRatioDOUBLE优化参数:用于全幅显示优化的面积比率SmCreateTimeDATETIME数据集创建时间SmLastUpdateTimeDATETIME数据集最后被更新的时间SmDynamicIndexINTEGER数据集是否已建立动态索引SmCreatorCHARACTER VARYING(32)数据集创建者(用户)SmProjectInfoBYTEA数据集投影信息SmParentIDINTERGER当前数据集父数据集的IDSmLockedUserIDINTERGER被锁定用户的IDSmDescriptionVARCHAR(256)数据集描述信息SmExtInfoVARCHAR(2048)数据集附加信息SmThumbLONGRAW数据集快照SmTotalGeometrySizeINTERGER数据集中几何对象的字节数SmTinToleranceDOUBLETin数据集里,金子塔使用 2、SmBandRegister—波段信息注册表 栅格数据集的波段信息管理表,新建一个栅格数据集,会根据波段数添加对应数目的记录,删除数据集的时候会删掉相应的记录。
字段名称字段类型描述SmBandIDSERIAL波段IDSmDatasetIDINTEGER所属数据集IDSmBandIndexINTEGER波段索引SmBandNameCHARACTER VARYING(64)波段名称SmBandFieldNameCHARACTER VARYING(64)波段所在字段名称SmBandAvailINTEGER是否可用(保留字段)SmOptionINTEGER选项信息,如是否压缩存储等SmScalarINTEGER当前波段保留字,用于新添加的像素格式SmEncTypeINTEGER编码类型SmPixelFormatINTEGER像素格式(如单色、16色、256色等)SmMaxBlockSizeINTEGER数据集中最大的Block的大小(字节数)SmMinZDOUBLE极小值SmMaxZDOUBLE极大值SmPyramidCHARACTER VARYING(64)影像金字塔底图数据集的名称SmPyramidLevelINTEGER影像金字塔的层数SmCreatorCHARACTER VARYING(64)创建者(用户)SmCreateTimeDATE创建时间SmDescriptionCHARACTER VARYING(256)描述信息SmNovalueDOUBLE无值SmPaletteBYTEA调色板 3、SmImgRegister—栅格数据集注册信息表 SmImgRegister表用来集中管理栅格数据集的信息,每新建一个栅格数据集,会在此表中新加一条记录,同样删除数据集时会将相应的记录从该表中移除。
字段名称字段类型描述SmDatasetIDINTEGER数据集的唯一编号SmDatasetNameCHARACTER VARYING(64)数据集名称(别名)SmTableNameCHARACTER VARYING(64)数据集表名SmDatasetTypeINTEGER数据集的类型SmEncTypeINTEGER数据集编码类型SmOptionINTEGER数据集的选项信息,如是否压缩存储等SmPixelFormatINTEGER像素格式(如单色、16色、256色等)SmWidthINTEGER图像宽度SmHeightINTEGER图像高度SmEBlockSizeINTEGER块的大小(像素)SmMaxBlockSizeINTEGER数据集中最大的Block的大小(字节数)SmMinZDOUBLE数据集最小高程值SmMaxZDOUBLE数据集最大高程值SmPyramidCHARACTER VARYING(64)影像金字塔底图数据集的名称SmPyramidLevelINTEGER影像金字塔的层数SmBlockSizesINTEGER块的大小(字节数)SmPaletteBYTEA调色板SmGeoLeftDOUBLE地理坐标四至SmGeoTopDOUBLE地理坐标四至SmGeoRightDOUBLE地理坐标四至SmGeoBottomDOUBLE地理坐标四至SmClipRegionBYTEA数据集的显示掩膜多边形SmCreateTimeDATETIME数据集创建时间SmLastUpdateTimeDATETIME数据集最后一次更新时间SmCreatorCHARACTER VARYING(32)数据集创建者(用户)SmDescriptionCHARACTER VARYING(256)数据集描述信息SmNoValueDOUBLE无值栅格SmProjectInfoBYTEA数据集投影信息SmColorSpaceINTEGER当前影像的默认色彩空间SmExtInfoVARCHAR(2048)数据集附加信息SmStatisticsInfosys.xmltype栅格数据集统计信息 4、SmDataSouceInfo—数据源相关信息表 SmDataSourceInfo表用来存储和数据源相关的信息。
字段名称字段类型描述SmFlagINTEGER数据源标志信息(保留待用)SmVersionINTEGER数据源版本号SmMinorVersionINTEGER数据源小版本号SmCoordSysINTEGER坐标系编码SmCoordUnitINTEGER坐标单位SmDistanceUnitINTEGER距离单位SmDsDescriptionVARCHAR(255)对数据源的描述SmProjectInfoLONGBINARY投影信息SmVersionDateINTEGER版本日期SmLastUpDateTimeDATE最后修改时间 5、SmDynamicIndex—动态索引信息表 SmDynamicIndex存储已建立动态索引的数据集信息。
字段名称字段类型描述SmDatasetIDINTEGER数据集IDSmIndexTableNameCHARACTER VARYING(64)索引表名称SmCenterPntXDOUBLE索引中心点X坐标SmCeneterPntYDOUBLE索引中心点Y坐标SmGridRatioDOUBLE网格比率SmGrid0DOUBLE第一层网格边长SmGrid1DOUBLE第二层网格边长SmGrid2DOUBLE第三层网格边长 6、SmFieldInfo—字段信息表 SmFieldInfo存储事件表数据集信息。
字段名称字段类型描述SmIDINTEGER字段标识IDSmDatasetIDINTEGER字段所在数据集IDSmFieldNameCHARACTER VARYING(64)字段名SmFieldCaptionCHARACTER VARYING(64)字段别名SmFieldTypeINTEGER字段类型SmFieldFormatCHARACTER VARYING(64)字段数值格式SmFieldSignINTEGER存储拓扑关系信息的字段SmFieldDomainCHARACTER VARYING(1024)字段域SmFieldUpdatableINTEGER字段是否可更新SmFieldSizeINTEGER字段长度 7、SmWorkspace—工作空间表 SmWorkspace存储工作空间信息。
进入到
/usr/share/icons/hicolor 查看到如下文件
1024x1024 128x128 16x16 192x192 20x20 22x22 24x24 256x256 32x32 36x36 480x480 48x48 512x512 64x64 72x72 96x96 apps icon-theme.cache index.theme scalable symbolic 在每一个 数字x数字的app文件下面找到对应的图标
例如下路径 /usr/share/icons/hicolor/256x256/apps 查看自己的应用是否加锁,如果加锁就执行
sudo chmod 777 [对应的图标] 查看如下文件夹下 对应的应用的图标是否是空白的,如果空白的从上面的文件夹中拷贝一份,后缀改成 .svg,重启电脑
/usr/share/icons/hicolor/scalable/apps/
目录
一、Nginx是什么?
二、下载nginx
三、Nginx配置
四、发布SPA项目以及虚拟域名设置
五、Tomcat集群配置
六、nginx动静分离
一、Nginx是什么? 代理服务器 --> Tomcat
HTML服务器
二、下载nginx 下载链接:http://nginx.org/download/nginx-1.17.10.ziphttp://nginx.org/download/nginx-1.17.10.zip
注1:此版本为window版本 linux版本
三、Nginx配置 解压软件至指定目录,例如:D:\tools\nginx-1.17.10
打开cmd容器,切换到nginx安装根目录,即可执行相关命令进行操作
start nginx.exe //启动nginx nginx.exe -s stop//快速停止nginxnginx.exe -s reload//重新加载nginxnginx.exe -s quit//完整停止nginx 注1:nginx默认使用80端口,这就是绝大多数网站对外的端口,网站其它端口应该都在防火墙的保护之下
注2:windows下nginx启动一闪而过且nginx启动失败,原因:有可能是80端口被占用的缘故,修改nginx端口即可
注3:如何修改nginx的端口号?
找到配置文件nginx_home/conf/nginx.conf
server {
#listen 80; #默认端口
listen 8088; #自定义端口
...
...
}
注4:nginx.conf文件中,#号为注解,代码必须以;号结尾
重要~~~~~~~~重要~~~~~~~~重要~~~~~~~~
四、发布SPA项目以及虚拟域名设置 1. 打包SPA项目,将打包后的dist目录复制到D:\tools\nginx-1.17.10\html,并更名为crm,最终SPA项目根目录为
D:\tools\nginx-1.17.10\html\crm 2. 修改server节点
server { listen 80; #监听80端口,可以改成其他端口 #server_name localhost; #当前服务的域名(虚拟域名也可以) server_name www.zking.com; #当前服务的域名(虚拟域名也可以) root html/crm; #将要访问的网站的根目录,nginx节点会自动继承父节点的配置 #charset koi8-r; #access_log logs/host.
Redis10大数据类型 Redis键(key)一、Redis字符串(string)1、最常用的2、获取指定区间范围内的值3、数值增减4、获取字符串长度和内容追加5、分布式锁(基础)6、getset 二、Redis列表(List)1、常用2、底层原理3、lpush\rpush\lrange4、lpop\rpop、lindex、len5、Irem key6、Itrim Key7、rpoplpush8、Iset key index value9、linsert key before/after 三、Redis哈希(Hash)1、常用<font color=red>2、hset/hget/hmset/hmget/hgetall/hdel3、hlen4、hexists key5、hkeys/hvals6、hincrby/hincrbyfloat7、hsetnx 四、Redis集合(set)1、常用2、增删改查3、SRANDMEMBER key [数字]4、SPOP key [数字]5、smove key1 key26、集合运算 五、Redis有序集合Zset(sorted set)1、常用2、添加和遍历3、获取指定分数范围的元素4、增删改查5、ZMPOP(New in 7.0)6、获得下标值 六、Redis位图(bitmap)1、简介常用2、setbit3、getbit4、统计字节数占多少5、bitcount6、bitop 七、Redis基数统计(HyperLogLog)1、常用 八、Redis地理空间(GEO)1、geoadd2、geopos3、geohash4、geodist5、georadius 九、Redis流(stream)1、底层原理2、队列相关指令XADDXRANGE\XREVRANGE\XDELXTRIMXREAD总结 3、消费组相关指令XGROUPXREADGROUP GROUP重点问题XPENDING XACK4、四个特殊符号 十、Redis位域(bitfield)1、常用命令2、溢出控制OVERFLOW [WRAPISAT FAIL] Redis键(key) 命令用途keys *查看当前库所有的keyexists key判断某个key是否存在type key查看你的key是什么类型del key删除指定的key数据unlink key非阻塞删除,仅仅将keys从keyspace元数据中州除,真正的删除会在后续异步中操作。ttl key查看还有多少秒过期,-1表示永不过期-2表示已过期expire key 秒钟为给定的key设置过期时间Bmove key dbindex 【0-15】将当前数据库的 key移动到给定的数据库db 当虫select dbindex切换数据库【0-15】,默认为0dbsize查看当前数据库key的数量flushdb清空当前库flushall通杀全部库 一、Redis字符串(string) 1、最常用的 set key value [NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]
Ex seconds:以秒为单位设置过期时间Fx milliseconds:以毫秒为单位设置过期时间BXAT time stamg:设置以秒为单位的UNIx时间戳所对应的时间为过期时间PXAI milliseconds-timestamp:设置以毫秒为单位的UNIx时间戳所对应的时间为过期时间NX:键不存在的时候设置键值XX:键存在的时候设置键值KEEPTTI:保留设置前指定键的生存时间GET:返回指定键原本的值,若键不存在时返回nil 命令解释SET key value设置指定 key 的值GET key获取指定key 的值。GETRANGE key start end返回 key 中字符串值的子字符GETSET key value将给定 key 的值设为 value,并返回 key 的旧值(old value)。GETBIT key offset对key 所储存的字符串值,获取指定偏移量上的位(bit)。MGET key1 [key2]获取所有(一个或多个)給定 key 的值。SETBIT key offset value对key 所储存的字符串值,设置或清除指定信移量上的位(bit)。SETEX key seconds value将值 value 关联到key,并将 key 的过期时间设为 seconds(以秒为单位)。SETNX key value只有在 key 不存在时设置 key 的值。SETRANGE key offset value用 value 参数覆写给定 key 所储存的字符牢值,从信移量 offiset 开始。STRLEN key返回 key 所储存的字符串值的长度。MSET key value [key value .
在开始正题之前,让我们先来看看本次学习的重难点。本次的知识点可以分为三个部分:
(1)常见的语法错误。
(2)基础语法中的常见异常。
(3)操作文件过程中的常见异常,这部分也是重难点知识。
编写代码时经常会遇到错误,因此掌握本课的内容对你将来自己做项目非常有帮助。至少可以节省大量排查错误的时间。加油!
1. 常见的语法错误
下面图片中显示的情况,相信你在平时写代码的过程中,肯定已经遇到过不少次了。
如果程序能够顺利运行,是不会出现这样的消息的。
这些在终端显示的"错误消息"表示我们在编写或运行程序时可能出现了问题。通常需要在Python中进行异常处理,以确保程序能够正确运行。
“异常处理”这个名词你应该是第一次接触,它包括我们在程序运行前的处理和在程序运行过程中的处理。
在Python中,异常处理是一门比较深奥的学问,涉及到很多特有的机制。不过我们暂时不需要掌握那么深入的知识,为了方便理解,你可以将解决问题或处理"错误消息"的过程称为"异常处理"。
不过,我们还不需要掌握这么难的知识,为了方便理解,你可以把解决问题或处理“错误消息”的过程称为“异常处理”。
我相信你凭借现有的编程经验,也能发现"错误消息"不仅限于图片中显示的那一种。实际上,按照Python官方文档的定义,这些"错误消息"至少可以分为两类:语法错误(syntax errors)和异常(exceptions)。
1.1 基本概念 语法错误(syntax errors)是初学者最容易犯的错误,简单来说就是代码不符合Python的基本语法规范,导致程序出错。
当你的代码完全符合Python的语法规范后,就可以尝试运行程序了。但是在程序运行过程中,仍然可能出现问题,我们称这类问题为异常。
作为一个有经验的人,为了让你少走弯路,我将根据你的技术水平列举一些常见的语法错误和异常。当然,我还会讲解它们产生的原因以及相应的解决办法。
此外,我还总结了一些在操作文件过程中可能遇到的常见异常,希望你引以为戒,尽量避免这些问题。
需要强调的是,本次讲解的语法错误和异常并不能代表全部,实际上,这只是冰山一角,还有许多复杂且棘手的异常等待你以后慢慢解决。
但是不要害怕,这是提高编程水平的必经之路。送你八个字:“遇事不慌,问题不大。”保持积极的心态是最重要的。
好了,按顺序,我们先来学习常见的语法错误。
正如前面所述,语法错误(syntax errors)是初学者最容易犯的错误,如果代码不符合 Python 的语法规范,比如漏了冒号,混用中英文符号等,就会出现这种错误。
如下图所示:
想要解决问题,最基本动作就是查看错误消息,终端会显示出现语法错误的那一行,并显示一个箭头^,指向这行里面检测到的第一个错误。
例如,在上图中,line 1和SyntaxError告诉你第一行有语法错误,出错位置很可能是在print() 附近。
需要说明的是,行数告诉你代码出现问题的位置,但不一定是最初出错的地方。有时候,真正的错误可能出现在提示信息所指示的位置之前,通常在前一行。
知道错误出现的位置后,就可以尝试解决错误了。下面我将分别讲解两种常见的语法错误:SyntaxError 和 IndentationError,以及它们产生的原因和相应的解决办法。
1.2 SyntaxError 第一种:SyntaxError: invalid syntax(无效语法)
在Python中,"SyntaxError: invalid syntax"是最常见的语法错误之一。它通常由以下几种情况引起:
一、遗漏了标点符号。
在第一种情况下,我们需要检查是否有遗漏标点符号。例如,在函数定义时,是否忘记了在括号后面加上冒号;在if条件判断和while循环中的条件后面是否有冒号;在for循环的可迭代对象后是否有冒号;以及在字典中的每个键值对之间是否有逗号等等。
此外,还要注意区分等于号(=)和等于比较运算符(==)的使用。
二、关键字拼写错误或遗漏。
第二种情况,很有可能是因为你手抖或者粗心,将 while 写成了 whlie,将 def 写成了 dfe 之类的错误,或者可能是你将 for...in... 中的关键字 in 忘写了。
三、变量名或函数名使用了关键字。
例:
# class 是 Python 的关键字,不可充当变量名class = False
导致该报错的原因为同时引用了torch和keras,并且在引包时出现先引用keras后引用torch的情况。
解决办法:将torch包引用语句提到keras前即可。
PCB叠层设计 一,4层板
方案1:top,gnd,pwr,bottom;此方案也是最常见的,主要元器件和关键信号在top。
方案2: top,pwr,gnd,bottom;此方案是主要元器件放bottom,很少用。
方案3:gnd,s1(pwr),s2(pwr),gnd;以插件dip元器件为主的pcb
二,6层板
方案1:top,gnd1,s1,pwr,gnd2,bottom, 常用方案,3个走线层和3个参考平面,
第三层是最好的走线层,关键信号走第三层s1(时钟,ddr), 底层走线排第2,顶层走线排第3。
方案2:top,gnd,s1,s2,pwr,bottom,4个走线层,2个参考平面。是从方案1优化来,多一个走线层,方便走更多的信号。第3层是最好的走线层。
三,8层板
方案1:top,gnd,s1,pwr,gnd,s2,gnd,bottom,常用方案,有多个参考平面,有很好的电磁吸收能力,4个走线层,4个参考平面。
记住常用最佳方案即可,叠层多的一般都是参考主芯片设计指南。
关键信号以地为参考平面,方便阻抗控制。多个地参考平面有利于电磁吸收。
PCB资料输出 gerber文件输出,记住一个命令 @camdocs
pads gerber文件是N+8, N是叠层数,以2层板为例。
top 顶层
bottom 底层
silkcreen top 丝印顶层
silkcreen bottom 丝印底层
solder mask top 阻焊顶层(露铜,不覆盖绿油)
solder mask bottom 阻焊底层 (露铜,不覆盖绿油)
paste mask top 钢网顶层
paste mask bottom 钢网底层
钻孔层
钻孔图
一般还会提供装配图,坐标位置,BOM表,IPC文件等给工厂。
以下链接可参考
PADS——导出Gerber文件_pads导出gerber文件_人生若只如初见645的博客-CSDN博客
PADS各层的意义及用途_mask (sohu.com)
总结: 简单工厂:一个工厂,通过type类型创建不同产品
工厂方法:每个产品一个工厂
抽象工厂:每个产品族一个工厂
1、简单工厂 根据传入的name进行创建对象,增删一个对象都要修改if else分支,不符合开闭原则;
public class AnimalFactory { //简单工厂设计模式(负担太重、不符合开闭原则) public static Animal createAnimal(String name) { if ("cat".equals(name)) { return new Cat(); } else if ("dog".equals(name)) { return new Dog(); } else if ("cow".equals(name)) { return new Dog(); } else { return null; } } } 2、工厂方法 工厂方法模式就很好的减轻了工厂类的负担,把某一类/某一种东西交由一个工厂生产;(对应简单工厂的缺点1。同时增加某一类 ”东西“ 并不需要修改工厂类,只需要添加生产这类 ”东西“ 的工厂即可,使得工厂类符合开放-封闭原则。 public interface PhoneFactory{ public void makePhone(); } public class IPhone implement PhoneFactory{ public void makePhone(){ System.
QMainWindow QMainWindow是用于创建应用程序的主窗口的类,通常用于创建具有复杂布局和多个功能区域的应用程序窗口。与QWidget和QDialog不同,QMainWindow提供了一个主要的菜单栏、工具栏、状态栏和中央部件,使得创建复杂的多文档界面(MDI)应用程序更加方便。它通常用于创建大型的桌面应用程序。 示例 #include "mainwindow.h" #include <QMenu> #include <QMenuBar> #include <QToolBar> #include <QStatusBar> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { // 创建动作 openfileact = new QAction(QIcon("open.png"), "Open"); // 打开文件动作 openfileact->setShortcut(QKeySequence(tr("Ctrl+O"))); // 设置快捷键 Ctrl+O copyfileact = new QAction(QIcon("copy.png"), "Copy"); // 复制动作 pastfileact = new QAction(QIcon("paste.png"), "Paste"); // 粘贴动作 setcoloract = new QAction(QIcon("color.png"), "Set Color"); // 设置颜色动作 // 创建菜单 QMenu *fileMenu = menuBar()->addMenu(tr("&File")); // 文件菜单 fileMenu->addAction(openfileact); // 将打开文件动作添加到文件菜单中 QMenu *editMenu = menuBar()->addMenu(tr("&Edit")); // 编辑菜单 editMenu->addAction(copyfileact); // 将复制动作添加到编辑菜单中 editMenu->addAction(pastfileact); // 将粘贴动作添加到编辑菜单中 QMenu *setMenu = menuBar()->addMenu(tr("
引言 Angular是一种流行的前端开发框架,被广泛用于构建现代化的Web应用。作为一名技术专家,我们需要深入了解Angular的核心原则和设计思想,并学会如何应用它来构建出色的Web应用。本篇博客将详细介绍Angular,包括其基本概念、关键组件以及实际案例。
1. Angular概述 Angular是一个基于TypeScript的开源JavaScript框架,由Google开发和维护。它采用了模块化、组件化和数据驱动的方式来构建Web应用。Angular提供了丰富的工具和功能,使得开发者可以快速构建响应式、可维护和可测试的应用。
2. Angular的核心组件 2.1 组件 组件是Angular中最重要的概念之一,它负责实现一个特定的UI组件,并处理与用户的交互。每个组件由模板(用于定义UI结构和布局)、样式表(用于定义组件的外观)和代码(用于处理逻辑和数据)组成。
import { Component } from '@angular/core'; @Component({ selector: 'app-example', templateUrl: './example.component.html', styleUrls: ['./example.component.css'] }) export class ExampleComponent { title = 'Example Component'; message = 'Hello, World!'; handleClick(): void { alert('Button clicked!'); } } 2.2 模块 模块是Angular应用的基本构建块,用于组织和管理组件、指令、管道和服务等功能模块。每个Angular应用至少有一个根模块,用于引导应用,并可以包含多个特性模块,用于组织功能。
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { ExampleComponent } from './example.component'; @NgModule({ declarations: [ ExampleComponent ], imports: [ BrowserModule ], providers: [], bootstrap: [ExampleComponent] }) export class AppModule { } 2.
美图欣赏2022/08/23 关于Python脚本如何执行另一个脚本,可以使用os.system()来实现
os.system(path) os.system()的参数:执行命令 + 执行内容 # os.system('python 脚本文件名') import os # 错误写法 os.system(r'E:\start.py') # 正确写法 os.system(r'python E:\start.py') 案例
在同一目录下有两个Python脚本文件,其中ATest.py执行BTest.py ATest.py
import os res = os.system('python BTest.py') # 打印执行结果 0表示success,1表示fail print(res) # 0 BTest.py print("My name is BTest.py")
代码
clear;clc
size=512;
block=8;
blockno=size/block;
LENGTH=size*size/64; Alpha1=0.02; Alpha2=0.02;
T1=100; I=zeros(size,size); D=zeros(size,size); BW=zeros(size,size); block_dct1=zeros(block,block);
i=imread('watermark64by64.png'); %水印原图
mark=reshape(i,1,LENGTH);
figure;imshow(i);title('水印');
%subplot(3,2,1);plot(mark);title('水印'); %显示原图
figure;I=imread('lena512512.jpg'); %需要加水印的原图
I0=I;
imshow(I);title('原始图像');
% BW=edge(I,'canny');figure;;imshow(BW);
% title('edge of origine image');
%嵌入水印
k=1;
for m=1:blockno
for n=1:blockno
x=(m-1)*block+1; y=(n-1)*block+1;
block_dct1=I(x:x+block-1,y:y+block-1);
block_dct1=dct2(block_dct1);
BW_8_8=BW(x:x+block-1,y:y+block-1);
if m<=1|n<=1
T=0;
else
T=sum(BW_8_8); T=sum(T);
end
if T>T1
Alpha=Alpha2;
else
Alpha=Alpha1;
end
block_dct1(1,1)=block_dct1(1,1)*(1+Alpha*mark(k)); block_dct1=idct2(block_dct1);
D(x:x+block-1,y:y+block-1)=block_dct1; k=k+1;
end
end
figure;imshow(D,[]);title('嵌入水印后的图像');
%提取水印
k=1;
mark1=[];
for m=1:blockno
for n=1:blockno
x=(m-1)*block+1; y=(n-1)*block+1;
使用vue格式化后端返回的金额,有小数保留小数,没有小数取整。
1. 在main.js中定义全局方法
// 金额格式化 Vue.prototype.$formatNumber = function (number) { // 将字符串转换为数字 number = parseFloat(number); if (isNaN(number)) { // 处理非法输入,例如无法转换为数字的字符串 return NaN; } else if (Number.isInteger(number)) { return parseInt(number); } else { return parseFloat(number.toFixed(2)); // 这里假设保留两位小数 } } 2. 使用
<template> <div> <div> ¥{{$formatNumber(price)}} </div> </div> </template> <script> export default { data() { return { price: '12.00' }; }, }; </script>
文章目录
目录
前言
一、顺序表简介
二、顺序表实现
1.接口的实现
2.方法具体实现
2.1构造方法
2.2 增加元素
2.3 判断是否包含某个元素并返回对应的位置
2.4获取对应位置元素、更改对应位置元素值
2.5删除操作、获取顺序表长度
三、 ArrayList使用
1.使用ArrayList
2.ArrayList的遍历
总结
前言 本章开始记录Java数据结构的学习过程,之前也有过数据结构的学习,现在想来是远远不够的,没有系统化的学习,现在从这里开始系统化的总结和分享Java数据结构的学习。
一、顺序表简介 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
二、顺序表实现 1.接口的实现 为了实现顺序表,接下来对部分方法进行实现。代码如下(示例):
public class SeqList { private int[] array;//待使用的顺序表 private int size;//计算顺序表存入的数据 SeqList(){ //无参构造方法 } SeqList(int initcapacity) { //有参构造方法,设置初始化的顺序表大小 } // 新增元素,默认在数组最后新增 public void add(int data) { } // 在 pos 位置新增元素 public void add(int pos, int data) { } // 判定是否包含某个元素 public boolean contains(int toFind) { return true; } // 查找某个元素对应的位置 public int indexOf(int toFind) { return -1; } // 获取 pos 位置的元素 public int get(int pos) { return -1; } // 给 pos 位置的元素设为 value public void set(int pos, int value) { } //删除第一次出现的关键字key public void remove(int toRemove) { } // 获取顺序表长度 public int size() { return 0; } // 清空顺序表 public void clear() { } } 2.
条件 设备1:windows 10系统笔记本(wifi和网口)
设备2:具有网口的计算机(假设IP为 192.13.100.200)
网线
期望 设备1通过wifi连接无线路由器访问互联网,设备2和设备1网线连接,设备2能通过设备1访问互联网。
步骤 设备1无线网配置
"设置" -> "网络和Internet" -> 右侧面板高级网络设置下点击"更改适配器选项"->右键 "WLAN" 选择属性 -> 共享选项卡下勾选 "允许其他网络用户通过此计算机的Internet连接来连接" -> "家庭网络连接" 下选择"以太网" -> 确认。
设备1 以太网配置
右键 "以太网" 选择属性 -> IPv4 -> IP已经被设为了192.168.137.1,子网掩码为255.255.255.0 -> "高级" -> 添加IP和子网掩码分别为 192.13.100.1 255.255.0.0 -> 确定
设备2 以太网配置
IP: 192.13.100.200
网络号(如有): 192.13.100.0
子网掩码: 255.255.255.0
网关设为: 192.13.100.1
DNS 服务器设为: 114.114.114.114
测试 在设备2 ping www.baidu.com
push之前先pull,解决冲突再推到远程仓库
前言
使用工具:Microsoft Visual Studio 2012
框架版本:.NET Framework 4.6
一、生成DLL
1.创建dll工程
2.编写dll函数
经过上述过程后工程中会生成几个自带的文件,可以在代码源文件对应的头文件中添加自己函数的声明
#ifndef PCH_H #define PCH_H #include<winnt.h> EXTERN_C _declspec(dllexport) int myAdd(int a, int b); EXTERN_C _declspec(dllexport) int myMax(int a, int b); #endif //PCH_H 然后在cpp文件中添加函数定义
// Dll1.cpp 与预编译头对应的源文件 #include "pch.h" #include "Dll1.h" int myAdd(int a, int b) { return a + b; } int myMax(int a, int b) { if (a > b) { return a; } else { return b; } //return 0; } 最后一步就是要生成dll和lib,只需要运行生成解决方案,即可
settings.py文件是Scrapy框架中用来配置爬取相关设置的文件。在Scrapy中,我们可以通过修改settings.py文件来自定义爬虫的行为,包括设置全局变量、配置下载延迟、配置ua池、设置代理以及其他爬虫相关的配置项。下面是对settings.py文件用法的详细解释和一个实例:
1.设置全局变量
在settings.py文件中,我们可以定义一些全局变量,这些变量在整个爬虫过程中都可以使用。例如,我们可以定义一个USER_AGENT变量,用来设置请求的User-Agent头信息: USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3' 2.配置下载延迟
在settings.py文件中,可以通过设置DOWNLOAD_DELAY参数来配置下载延迟,以控制爬取速度。DOWNLOAD_DELAY的单位是秒,可以设置为1或更大的值。例如: DOWNLOAD_DELAY = 1 3.配置UA池
为了防止网站对爬虫的识别,我们可以设置一个User-Agent池,让每个请求随机选择一个User-Agent进行发送。可以在settings.py文件中设置USER_AGENT_POOL,如下所示: USER_AGENT_POOL = [ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:78.0) Gecko/20100101 Firefox/78.0', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebK... ] 然后,在Spider中随机选择一个User-Agent进行请求发送:
from scrapy import Spider from scrapy.utils.project import get_project_settings from scrapy.utils.httpobj import urlparse_cached class MySpider(Spider): name = 'my_spider' def __init__(self, name=None, **kwargs): self.
1.安装MySQL主容器 1.1首先,使用以下命令创建MySQL主容器:
sudo docker run --name mysql-master -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:latest
在这里,使用了Docker官方提供的MySQL镜像,并且使用了MySQL的默认3306端口。--name表示给该主容器设置一个名字,-p表示设置端口,-e选项用于设置MySQL的root密码,-d表示后台运行该容器。
然后使用sudo docker ps -a查看该进程
1.2配置MySQL主容器
使用以下步骤配置MySQL主容器:
1.2.1.连接MySQL主容器 使用以下命令连接到MySQL主容器:
sudo docker exec -it mysql-master bash
1.2.2.创建数据库和用户 在连接到MySQL主容器后,使用以下命令创建一个名为mydb的数据库,并创建一个名为myuser的用户:
mysql -uroot -p123456 -e "create database mydb;"
mysql -uroot -p123456 -e "create user 'myuser'@'%' identified by 'mypassword';"
mysql -uroot -p123456 -e "grant all privileges on mydb.* to 'myuser'@'%';"
结果如下: 1.2.3.启用二进制日志 使用以下命令启用MySQL主容器的二进制日志功能:
mysql -uroot -p123456 -e "set global log_bin_trust_function_creators=1;" mysql -uroot -p123456 -e "
getdate(startTime, endTime){ var start = startTime.split(/[- : \/]/); var date1 = new Date(start [0], start [1]-1, start [2], start [3], start [4], start [5]); var end=endTime.split(/[- : \/]/); var date2 = new Date(end[0], end[1]-1, end[2], end[3], end[4], end[5]); var c1 = date2.getTime()-date1.getTime();//毫秒差 var c2 = (date2.getTime()-date1.getTime())/1000;//秒差 console.log(this.formatSeconds(c2)) }, formatSeconds(value) { var theTime = parseInt(value);// 需要转换的时间秒 var theTime1 = 0;// 分 var theTime2 = 0;// 小时 var theTime3 = 0;// 天 if(theTime > 60) { theTime1 = parseInt(theTime/60); theTime = parseInt(theTime%60); if(theTime1 > 60) { theTime2 = parseInt(theTime1/60); theTime1 = parseInt(theTime1%60); if(theTime2 > 24){ //大于24小时 theTime3 = parseInt(theTime2/24); theTime2 = parseInt(theTime2%24); } } } var result = ''; if(theTime3 > 0) { result = "
01输入输出 NP1 Hello World!NP2 多行输出NP3 读入字符串NP4 读入整数数字NP5 格式化输出(一)NP6 牛牛的小数输出 NP1 Hello World! import sys str = 'Hello World!' print(str) for line in sys.stdin: a = line.split() print(int(a[0]) + int(a[1])) Tips:要会定义变量
NP2 多行输出 import sys str1='Hello World!' str2='Hello Nowcoder!' print(str1) print(str2) for line in sys.stdin: a = line.split() print(int(a[0]) + int(a[1])) Tips:要会定义变量,打印变量
NP3 读入字符串 import sys Nowcoder=input('') print(Nowcoder) for line in sys.stdin: a = line.split() print(int(a[0]) + int(a[1])) Tips:要会函数input('提示输出信息 ')
目录
1. 程序入口
2. __name__
3. __main__.py 文件与 python -m
if __name__ == '__main__' 简单的理解就是: 如果模块是被直接运行的,则代码块被运行,如果模块是被导入的,则代码块不被运行。
1. 程序入口 对于很多编程语言来说,程序都必须要有一个入口,比如 C,C++,以及完全面向对象的编程语言 Java,C# 等。如果你接触过这些语言,对于程序入口这个概念应该很好理解,C 和 C++ 都需要有一个 main 函数来作为程序的入口,也就是程序的运行会从 main 函数开始。同样,Java 和 C# 必须要有一个包含 Main 方法的主类来作为程序入口。
而 Python 则有不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。
一个 Python 源码文件除了可以被直接运行(run)外,还可以作为模块(也就是库)被导入(import)。不管是导入还是直接运行,最顶层的代码都会被运行(Python 用缩进来区分代码层次)。而实际上在导入的时候,有一部分代码我们是不希望被运行的。
举一个例子来说明一下,假设我们有一个 const.py 文件,内容如下:
PI = 3.14 def main(): print "PI:", PI main() 我们在这个文件里边定义了一些常量,然后又写了一个 main 函数来输出定义的常量,最后运行 main 函数就相当于对定义做一遍人工检查,看看值设置的都对不对。然后我们直接执行该文件(python const.py),输出:
PI: 3.14 现在,我们有一个 area.py 文件,用于计算圆的面积,该文件里边需要用到 const.py 文件中的 PI 变量,那么我们从 const.py 中把 PI 变量导入到 area.
一、redis启动
本地启动:redis-cli
远程启动:redis-cli -h host -p port -a password
Redis 连接命令
1 AUTH password
验证密码是否正确
2 ECHO message
打印字符串
3 PING
查看服务是否运行
4 QUIT
关闭当前连接
5 SELECT index
切换到指定的数据库
二、redis keys命令
1、DEL key
DUMP key
序列化给定的key并返回序列化的值
2、EXISTS key
检查给定的key是否存在
3、EXPIRE key seconds
为key设置过期时间
4、EXPIRE key timestamp
用时间戳的方式给key设置过期时间
5、PEXPIRE key milliseconds
设置key的过期时间以毫秒计
6、KEYS pattern
查找所有符合给定模式的key
7、MOVE key db
将当前数据库的key移动到数据库db当中
8、PERSIST key
移除key的过期时间,key将持久保存
9、PTTL key
以毫秒为单位返回key的剩余过期时间
10、TTL key
以秒为单位,返回给定key的剩余生存时间
11、RANDOMKEY
从当前数据库中随机返回一个key
vue3 ref、reactive toRefs setup + ref + reactive 实现了数据响应式,不能使用 ES6 解构,会消除响应特性。所以需要 toRefs 解构,使用时,需要先引入。
let me = reactive({ single:true, want:"暖的像火炉的暖男" }) //运行为 let me = proxy : { single: true, want:"暖的像火炉的暖男" } const { single, want } = toRefs( me ) toRef toRef作用:将对象某一个属性,作为引用返回。
let me = reactive({ single:true, want:"暖的像火炉的暖男" }) let lv = toRef( me, 'love' ) console.log('love',love); //打印结果 ObjectRefImpl { __v_isRef: true _key: "love" _object: Proxy {single: true, want: "
成功解决RuntimeError: CUDA error: invalid device ordinal
之前在跑代码的时候需要指定GPU出现了下面的这种情况:
导致上述情况的可能性主要是下面的原因:
用的Pytorch分布式代码,指定的每个节点GPU个数和你指定的GPU序号不对应(我出错的地方就是在这里)
CUDA_VISIBLE_DEVICES=2,3 python -m torch.distributed.launch --nproc_per_node=3 --nnodes=1 --node_rank=0 --master_addr=“127.0.0.1” --master_port=1234 train.py
通过nnodes指定总共使用1个节点,通过nproc_per_node指定了该节点启3个进程,但是前面CUDA_VISIBLE_DEVICES就只指定了两个GPU,对应不起来导致的。另:rank表示的结点之间的主、从关系。
参考:https://blog.csdn.net/qxqxqzzz/article/details/107720675
用于日常排错,自用。其他小伙伴跟我不一样的错误可以参考我给出博客地址,看看自己到底是哪里除了错误。
模块的划分
所谓软件的模块划分是指在软件设计过程中,为了能够对系统开发流程进行管理,保证系统的稳定性以及后期的可维护性,从而对软件开发按照一定的准则进行模块的划分。根据模块来进行系统开发,可提高系统的开发进度,明确系统的需求,保证系统的稳定性。
在系统设计的过程中,由于每个系统实现的功能不同,所以每个系统的需求也将会不同。也就导致了系统的设计方案不同。在系统的开发过程中,有些需求在属性上往往会有一定的关联性,而有些需求之间的联系很少。如果在设计的时候,不对需求进行归类划分的话,在后期的过程中往往会造成混乱。
在系统定义和软件计划等阶段进行基本模型设计时,以底层功能为单位,对处理、输入、输出、文件等进行了初步的研究和设定,并且研究了人机接口等问题,但是,以此新系统基本模型设计为基础所做出的各层次基本模型都只是表达出了各个业务处理之间的自然逻辑,并没有表达出计算机处理的流程。
因此,在具体着手软件设计工作之前,有必要先对基本模型图中规定为计算机处理的部分进行处理模块的划分,以便大体上明确其处理的流程。当然,这时候所划分的处理模块还不能包含具体的物理内容 (例如,其中的输入、输出和文件等仍然只能是抽象的) 。因为这些物理内容正是需要通过以后的设计工作才能逐步具体起来。
软件设计过程中通过对软件进行模块划分可以达到一下的好处:
(1)使程序实现的逻辑更加清晰,可读性强。
(2)使多人合作开发的分工更加明确,容易控制。
(3)能充分利用可以重用的代码。
(4)抽象出可公用的模块,可维护性强,以避免同一处修改在多个地方出现。
(5)系统运行可方便地选择不同的流程。
(6)可基于模块化设计优秀的遗留系统,方便的组装开发新的相似系统,甚至一个全新的系统。
系统性能的衡量标准
计算机处理模块的划分使新系统从基本 (逻辑) 模型向实际的计算机处理系统迈开了第一步。显然,模块划分的好坏将会影响软件乃至整个系统性能的优劣。
不同的对象对系统性能的要求有所不同,要制订出适应于所有系统的衡量标准,以判别系统性能的优劣是有困难的。一般软件系统性能的衡量标准主要有以下四个方面的内容:
(1)系统效率
对于批处理系统来说,指的是单位时间内处理的业务量;对于联机实时处理系统来说,则主要是指响应时间。
(2)系统工作质量
主要是指系统信息处理的质量,例如所提供数据的精度、输出报表的易读性等等。
(3)系统可靠性
是指系统抵御各种外界干扰的能力。例如,输入的错误数据能否检查出来;文件中数据一旦被破坏能否恢复;电源断电等意外事故发生时,有无应急措施等等。
(4)系统的可维护性
是指纠正系统出现的错误和缺陷,以及为满足新的要求进行扩充或压缩的容易程度。应该看到,任何系统都不可能永久不变,由于环境变化等诸因素,系统需要不断地进行修改和完善。
上述四个衡量标准中,可维护性占有很重要的地位。因为如果系统的其他指标都很好,唯独可维护性很差,那么一旦由于某些条件的改变需要对系统进行修改时,就会因此而无法进行修改,最后不得不重新设计系统。相反,如果系统的可维护性很好,那么,尽管其他指标差一些,也可以在使用中进一步进行修改,并逐步加以完善。
软件结构
软件结构表示程序的系统结构,它以层次结构表示一种控制层次体系,它并不表示软件的具体过程 (例如各个进程的顺序、判定和操作重复等) 。
软件结构表示了软件元素 (模块) 之间的关系,例如调用关系、包含关系、从属关系和嵌套关系等。下图表示了一个软件结构。
(1)深度
深度表示软件结构中控制层数。例如图4-1是一个四层软件结构。深度往往能粗略地表示一个系统的大小和复杂程度,软件结构的深度和程序长度之间存在着某种对应关系。
(2)宽度
宽度是软件内同一层次上的模块总数。一般来说,结构的宽度越大,则系统就越复杂。
(3)扇出
扇出是由一个模块直接控制的其他模块数的一种度量。例如图4-1中模块A,B,C,D的扇出分别为3,2,1,2。扇出过大,表示模块过分复杂,需要控制和协调的下级模块太多。扇出的上限一般为5~9,平均一般为3或4。
(4)扇入
扇入表示有多少个上级模块直接控制一个给定的模块。例如图4-1中模块R和S的扇入分别为3和1。扇入过大,意味着共享该模块的上级模块数目多,这有一定的益处,但是决不能违背模块的独立性原则而片面追求高扇入。
模块划分的方法
很多人都参与过一些项目的设计,在很多项目设计过程中对于模块划分大多都是基于功能进行划分。这样划分有一个好处,由于在一个项目的设计过程中,有着诸多的需求。而很多需求都可以进行归类,根据功能需求分类的方法进行模块的划分。可以让需求在归类上得到明确的划分,而且通过功能需求进行软件的模块划分使得功能分解,任务分配等方面都有较好的分解。
按照任务需求进行模块划分是一种基于面向过程的划分方法,利用面向过程的思想进行系统设计的好处是能够清晰的了解系统的开发流程。对于任务的分工、管理,系统功能接口的制定在面向过程的思想中都能够得到良好的体现。
按任务需求进行模块划分的主要步骤如下:
(1)分析系统的需求,得出需求列表;
(2)对需求进行归类,并划分出优先级;
(3)根据需求对系统进行模块分析,抽取出核心模块;
(4)将核心模块进行细化扩展,逐层得到各个子模块,完成模块划分。
在很多情况下,在划分任务需求的时候,有些需求和很多个模块均有联系,这个时候,通过需求来确定模块的划分就不能够降低模块之间的耦合了。而且有些模块划分出来里面涉及的数据类型多种多样,显然这个时候根据系统所抽象出来的数据模型来进行模块划分更加有利。
在系统进行模块划分之前,往往都会有一个数据模型的抽象过程,根据系统的特性抽象出能够代表系统的数据模型。根据数据模型来进行模块划分,可以充分降低系统之间的数据耦合度。按照数据模型进行模块的划分,降低每个模块所包含的数据复杂程度,简化数据接口设计。同时,对于数据的封装可以起到良好的作用,提高了系统的封闭性。
抽象数据模型的模块划分方案是一种基于面向对象的思想进行的。这种思想的特点就是不以系统的需求作为模块的划分方法,而是以抽象出系统的数据对象模型的思想对模块进行划分。而利用这种思想进行模块划分的主要好处能够接近人的思维方式对问题进行划分,提高系统的可理解性,可以从较高层次上对系统进行把握!
按照数据模型进行模块划分的主要步骤如下:
(1)根据系统框架抽象出系统的核心数据模型;
(2)根据核心数据模型将系统功能细化,并将数据模型与视图等剥离,细化数据的流向;
(3)依据数据的流向制定模块和接口,完成模块划分。
模块划分的基本原则
“模块”实际上是一个已经得到广泛应用的概念,许多程序设计语言中的所谓子程序、分程序、过程、函数等实质上都具有模块的特性。这些特性包括模块的名字、输入和输出信息、功能、内部逻辑构造、可被调用以及可调用其他模块等。
既然系统的可维护性是评价系统性能的首要因素,那么,应该怎样做才能使系统变得容易修改呢?通常一个系统是由若干个子系统组成的;每个子系统又可分解成更小的子系统。在实际工作中,要求改变整个系统的结构的情况是极为少见的。所谓系统的修改往往只是对某些子系统的某些细节作一些变动,也就是说,这些修改通常都是局部的。
然而,由于各子系统之间是相互关联的,对其中某个子系统的修改,可能会通过这些相互关系而影响到其他子系统,乃至波及整个系统。这样,就可能会造成动了一处而引出来好几处的问题,越改越乱,甚至会出现使修改工作无法进行下去的局面。
由此可见,要使系统易于修改,必须使每一个修改都尽可能地局部化。这就要求在进行系统的模块划分时,要使模块的内部联系尽可能地强,而模块间的外部联系尽可能地弱,即尽可能地提高模块的相对独立性。这样,在对其中某一个模块作修改时,它所造成的影响只局限在本模块范围内,而不至于波及整个系统。
当系统被划分成若干个模块之后,模块之间的关系称之为块间关系,而模块内部的实现逻辑都属于模块内部子系统。对于软件的模块划分要遵循一些基本原则,遵循基本原则进行模块划分所设计出来的系统具有可靠性强,系统稳定,利于维护和升级。
设计模块往往要注意很多的问题,好的模块划分方案可以对系统开发带来很多的便利,提高整个系统的开发效率,而且对于系统后期的维护难度也会降低不少。反之,如果模块划分的不恰当,不仅不能带来便利,往往还会影响程序的开发。
在进行软件模块划分的时候,首先要遵从的一个准则就是确保每个模块的独立性,所谓模块独立性,即:不同模块相互之间的联系尽可能少,尽可能的减少公共的变量和数据结构。每个模块尽可能的在逻辑上独立,功能上完整单一,数据上与其他模块无太多的耦合。
模块独立性保证了每个模块实现功能的单一性,接口的统一性,可以将模块之间的耦合度充分降低。在进行软件模块划分的时候,如果各个模块之间的联系过多,模块独立性差容易引起系统结构混乱,层次划分不清晰。导致有的需求和多个模块均有关联,严重影响系统设计。
对于模块独立性的好处主要可以归纳为以下几点:
(1)模块功能完整独立;
项目结构 模板语法(在标签之外) 插值语法 :双大括号
属性绑定(在标签之内) v-bind:
单属性两种写法 多属性绑定
条件渲染 列表渲染 要有key,降低消耗
遍历数组
遍历对象 事件处理 传递参数 事件修饰符 数组监听(后续研究) (当数组方法不会产生新数组,自己替换新数组来实现数组监听)
计算属性 计算属性只有一次,方法每次都会调用
监听属性 class绑定 style绑定 表单绑定 模板操作 组件 局部引用 全局引用(在main中) 数据传递 props(父传子) 子添加props属性
传参校验 类型 默认值 必须选性 组件事件(子传父) 触发自定义事件类型
传递函数(子传父) 父元素向子元素传递函数,子元素调用函数来更改父元素的数据,实现子传父
父
子
插槽 组件嵌套过程中,父组件内部向子元素插入其他东西。
具名插槽 动态组件 保持活性 异步组件(懒加载) 依赖注入(参数透传) 祖宗
子(类似props) 路由 懒加载 通过箭头函数实现懒加载
Vuex Vue有五个核心概念,state, getters, mutations, actions, modules。
state => 基本数据getters => 从基本数据派生的数据mutations => 提交更改数据的方法,同步!actions => 像一个装饰器,包裹mutations,使之可以异步。modules => 模块化Vuex Getters Mutation Actions