ArrayList.add()和asList().add()的问题 在使用asList().add()操作的时候报异:UnsupportedOperationException
原因及分析 asList()他所使用的是Arrays的内部类ArrayList,此内部类未重写add()方法,所以这里使用的add方法就是ArrayList类的父类abstract类,这里的add()方法默认就是抛异常:UnsupportedOperationException
Arrays的内部类
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -2764017481108945198L; private final E[] a; ArrayList(E[] array) { a = Objects.requireNonNull(array); } @Override public int size() { return a.length; } @Override public Object[] toArray() { return a.clone(); } @Override @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { int size = size(); if (a.length < size) return Arrays.copyOf(this.a, size, (Class<? extends T[]>) a.
有两种方法
通过xx[xx]的方式获取属性值,key是动态的,可以是字符串,也可以是数字,还可以是变量
xx.xx点方法后面的属性名不能是数字
Win11 Word图标变成白色怎么恢复?有一些朋友发现自己电脑上的doc格式的word文档图标是白色的,这是怎么回事呢?出现这种情况应该如何解决?大家肯定要先确保电脑上有安装Office软件,今天给朋友们讲讲具体的解决方法,让word文档图标显示恢复正常。
以下一键重装系统的步骤可阅读
方法1:
1、首先我们在文档上点击鼠标右键,移至【打开方式】,点击【选择其他应用】。
2、然后在“你要如何打开这个文件”窗口找到WPS软件或者微软的Office软件,勾选【始终使用此应用打开文件】。
这样一来Word图标就恢复正常了。
方法2:
1、点击开始菜单,在搜索框里输入【默认应用】并打开。
2、往下拖动找到WPS Office软件或者Microsoft Office软件,点击进去。
3、点击Word文档对应的后缀名doc和docx,就可以更改默认用什么软件打开。
情况二:office程序损坏
这种情况下,已经没办法使用原有的程序打开软件,需要重新安装Office,安装完成后重新打开文档文件即可。
Win11 Word图标变成白色怎么恢复?有一些朋友发现自己电脑上的doc格式的word文档图标是白色的,这是怎么回事呢?出现这种情况应该如何解决?大家肯定要先确保电脑上有安装Office软件,今天给朋友们讲讲具体的解决方法,让word文档图标显示恢复正常。
以下一键重装系统的步骤可阅读
方法1:
1、首先我们在文档上点击鼠标右键,移至【打开方式】,点击【选择其他应用】。
2、然后在“你要如何打开这个文件”窗口找到WPS软件或者微软的Office软件,勾选【始终使用此应用打开文件】。
这样一来Word图标就恢复正常了。
方法2:
1、点击开始菜单,在搜索框里输入【默认应用】并打开。
2、往下拖动找到WPS Office软件或者Microsoft Office软件,点击进去。
3、点击Word文档对应的后缀名doc和docx,就可以更改默认用什么软件打开。
情况二:office程序损坏
这种情况下,已经没办法使用原有的程序打开软件,需要重新安装Office,安装完成后重新打开文档文件即可。
文章目录 前言一、使用字符数组二、使用字符数组和字符结合三.字符串处理函数 前言 C语言中没有提供字符串的数据类型,一般用字符数组存储字符串。
如果要输入输出字符串怎么办呢?下面三种方法可供参考。
一、使用字符数组 1.示例:
char str[100]={0};//定义一个一维字符数组用来存放字符串 scanf("%s",str);//以字符串的形式输入字符串 printf("%s",str);//以字符串的形式输出字符串 2.缺点:
只能输入不含空格的一行字符串。如果输入的字符串中含有空格,则只会打印出第一个空格之前的子字符串。
二、使用字符数组和字符结合 1.示例:
int main() { char ch = '0'; int i = 0; char str[100] = { 0 }; while ((ch = getchar()) != '\n') { str[i] = ch; i++; } printf("%s", str); return 0; } 2.说明:
getchar()函数是从控制台获取一个字符的函数。这种方法是通过获取一个一个字符,然后再将字符放到字符数组中,最后打印出字符串。虽然有点麻烦,但能够打印出具有空格的一行字符串。
三.字符串处理函数 1.示例:
int main() { char str[100] = { 0 }; gets(str); printf("%s", str); return 0; } 2.说明:
有3个数据源
t100019、t100049、t100138
本文旨在使用springboot、AOP、AbstractRoutingDataSource实现多数据源的动态切换
1.导入数据源、aop等相关依赖 <properties> <java.version>1.8</java.version> <aspectjrt.version>1.9.1</aspectjrt.version> <aspectjweaver.version>1.9.1</aspectjweaver.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.13</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.0.3.RELEASE</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${aspectjrt.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectjweaver.version}</version> </dependency> </dependencies> 2.配置文件配置如下 server.port=8889 spring.datasource.t100019.username=root spring.datasource.t100019.password=root spring.datasource.t100019.url=jdbc:mysql://127.0.0.1:3306/t100019?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true spring.datasource.t100019.driver-class-name=com.mysql.jdbc.Driver spring.datasource.t100019.type=com.alibaba.druid.pool.DruidDataSource spring.datasource.t100049.username=root spring.datasource.t100049.password=root spring.datasource.t100049.url=jdbc:mysql://127.0.0.1:3306/t100049?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true spring.
查询mysql所有表数据、字段信息 根据库名获取所有表的信息 SELECT * FROM information_schema.`TABLES` WHERE TABLE_SCHEMA = 'erp'; 根据库名获取所有表名称和表说明 SELECT TABLE_NAME, TABLE_COMMENT FROM information_schema.`TABLES` WHERE TABLE_SCHEMA = 'erp'; 根据库名获取所有的字段信息 SELECT TABLE_SCHEMA AS '库名', TABLE_NAME AS '表名', COLUMN_NAME AS '列名', ORDINAL_POSITION AS '列的排列顺序', COLUMN_DEFAULT AS '默认值', IS_NULLABLE AS '是否为空', DATA_TYPE AS '数据类型', CHARACTER_MAXIMUM_LENGTH AS '字符最大长度', NUMERIC_PRECISION AS '数值精度(最大位数)', NUMERIC_SCALE AS '小数精度', COLUMN_TYPE AS 列类型, COLUMN_KEY 'KEY', EXTRA AS '额外说明', COLUMN_COMMENT AS '注释' FROM information_schema.`COLUMNS` WHERE TABLE_SCHEMA = 'erp' ORDER BY TABLE_NAME, ORDINAL_POSITION; 根据库名获取所有的库和表字段的基本信息 SELECT C.
Python OCR工具pytesseract,之前是惠普的产品,被Google收了之后就给开源了。
1、需要下载并安装Google Tesseract,下载地址看图片上有,要下载4.0.0版本的
2、下载打开后双击打开,选择安装位置,然后一路下一步即可安装完成
3、安装完成需要设置一下环境变量,设置环境变量需自行百度,非常简单
4、安装所需要的Python模块,直接执行以下命令
pip install pillow==9.2.0
pip install pytesseract==0.3.9
5、最后还需要一个语言包文件:chi_sim.traineddata,这个文件需翻墙才能下,有需要的找我可以发给他
注:我的Python版本是3.7,3.8也是可以的,但3.9及以上会出问题,建议你也用3.7
Tesseract下载地址:https://digi.bib.uni-mannheim.de/tesseract/
代码如下:
# encoding=utf8 ''' Python批量识别图片中的文字并保存到txt文档中 ''' # 导入包 from PIL import Image import string,re,os import pytesseract # 定义方法 def imgtostr(imgpath): '''识别图片中的所有文字''' image = Image.open(imgpath) text = pytesseract.image_to_string(image, lang = 'chi_sim') # 使用简体中文解析图片 return text.replace("\n", "") # 去掉换行 def writefile(txtpath,strstr): '''将文字累加并写入txt文档''' with open(txtpath, "a", encoding= "utf-8") as f: f.write(strstr) # 写入文件 f.write("\n\n") if __name__ == '__main__': # 存放待识别图片的目录,支持所有图片格式 imgpath = r'D:\Test\image' # 识别结果保存的txt文件路径 txtpath = r'D:\Test\word.
数据中台的概念由阿里巴巴首次提出,它的目的是将企业沉睡的数据变成数据资产,从而实现数据价值变现的系统和机制。本文小编从什么是数据中台、数据中台的价值、数据中台必备的能力和一些优质的数据中台的架构图模板来展开说明。
01
什么是数据中台?
2016年前后,随着互联网的高速发展,数据应用的需求变多,为快速响应业务需求,许多企业开始存在不同程度的烟囱式的开发模式,这种烟囱式的开发导致企业不同业务线的数据割裂,造成了数据的重复加工、研发效率、数据存储和计算资源的严重浪费,大数据的应用成本越来越高,同时带来指标口径不一致等问题。于此同时,阿里巴巴提出“数据中台”的口号。它的核心是:避免数据的重复加工,通过数据服务化,提高数据的共享能力,赋能数据应用。
点击查看模板原图
这张图从什么是数据中台、什么是中台、数据平台的演进之路、中台总结四个方面对数据中台做了基础介绍,方便大家对数据中台有一个入门了解。
02
数据中台的价值
数据中台的核心工作并不是将企业的数据全部收集起来做汇总就够了,它的使命是利用大数据技术、通过全局规划来整合好企业的数据资产,让数据使用者能随时随地获取到可靠的数据。因此,数据中台一旦建成并得以持续运营,其价值将随着时间的推移将呈指数级增长。
点击查看模板原图
03
数据中台必备的能力
数据中台需要具备数据汇聚整合、数据提纯加工、数据服务可视化、数据价值变现4个核心能力,让企业员工、客户、伙伴能够方便地应用数据。
点击查看模板原图
04
数据中台架构图案例
按照惯例,小编为正在整理数据中台架构的小伙伴准备了8张数据中台架构模板,可以给大家提供一些思路。想了解更多数据中台的内容,ProcessOn的模板库还有非常多的资源,大家搜索关键词即可查询到哦。
1、数据中台整体架构图
点击查看模板原图
2、企业数据中台整体解决方案
点击查看模板原图
3、通用数据中台解决方案架构规划
点击查看模板原图
4、运维数据中台参考架构图
点击查看模板原图
5、工业数据中台系统架构
点击查看模板原图
6、数据中台微服务架构图
点击查看模板原图
7、数据资产管理平台
点击查看模板原图
8、阿里巴巴数据中台全景图
点击查看模板原图
9、紫金保险数据中台技术架构图
点击查看模板原图
数据时代带来的挑战不仅是数据量的爆发式增长,更重要是如何管理好、处理好、利用好这些数据,很显然,传统的大数据建设方法论已无法满足企业的需求,那么大数据平台开发和管理工具的使用,才能助力企业有更大的发展。
在Android开发过程中,ANR问题可能是非常常见的一个问题,下面我分享一个亲身经历的ANR问题以及解决方法。
1.发生ANR 必然会有log日志,在系统的data/anr目录下, 我们将所有的anr log日志pull出来 由于权限的原因,一般使用:
adb pull /data/anr/anr_2022-08-04-19-43-53-830 ./ 会提示:
adb: error: failed to copy '/data/anr/anr_2022-08-04-19-43-53-830' to './/anr_2022-08-04-19-43-53-830': remote open failed: Permission denied 如果倒不出来,可以采用
adb bugreport 执行这个命令之后会在/home/ms(这里是我的路径)生成一个zip文件: bugreport-crosshatch-SPB5.210812.002-2022-08-04-19-52-30.zip
将这个zip解压开得到:
在/FS/data/anr 下面就是产生anr的日志文件
打开最新的一个anr日志文件,内容很多,可以通过搜索 main来快速定位到日志:
"main" prio=5 tid=1 Native | group="main" sCount=1 ucsCount=0 flags=1 obj=0x71bb1108 self=0x7aaf011010 | sysTid=11840 nice=-10 cgrp=default sched=0/0 handle=0x7be4f0a4f8 | state=R schedstat=( 34563882813 172228872 5118 ) utm=3400 stm=55 core=6 HZ=100 | stack=0x7fc17f0000-0x7fc17f2000 stackSize=8188KB | held mutexes= native: #00 pc 00000000005f29dc /data/app/~~HpEMONV-UKwHtGltDb4G-w==/com.
来源:DataFunTalk 本文约3000字,建议阅读5分钟本文以一位读者在实际业务中遇到的问题为切入点,和大家分享模型策略的分析方法。 [ 导读 ] 做风控的同学都知道,要做好一个模型可能已经有一定的难度:需要我们构建适合于解决问题的样本、清晰定义目标变量、加工并选择好的特征、采用合适的模型方法等,每一步都要避免其中的各种“坑”。然而,当我们做了一系列模型之后,可能又会面临一个更加考验技巧的任务——如何有效地应用好模型,尤其是有多个模型的情况下,如何制定恰当的应用策略方法。
图1 读者遇到的业务难题
01、模型策略分析方法
模型策略是基于已有风控模型制订最优决策的整体方法,它决定了模型价值是否能够被充分发挥,直接影响信贷业务的盈利水平。模型策略分析流程主要包含样本提取、模型策略的制订、模型策略评估、模型策略的上线与验证,以及模型策略回顾,如图2所示。
图2 模型策略分析路程
1. 样本选取
样本选取是指选取制订模型策略所需的样本集,通常包含风控模型开发时的跨时间验证集(OOT)和近期授信样本集(BackScore),如图3所示。在模型策略开发中,我们只需要准备模型分和逾期标签。跨时间验证集包含逾期标签,一般是近期放款且有表现的样本集,主要用于衡量同时期新模型相对于旧模型的模型效果提升度和制订决策点(Cut-off)时的效果预估。近期授信样本集是指近期所有进入模型打分阶段的样本集,包含被模型通过和拒绝的所有样本,主要用于设定新模型在预期通过率下的模型阈值。
图3 模型策略样本划分
跨时间验证集需要包含订单标识、模型分和逾期标签列,近期授信样本集需要包含订单标识和模型分列。
2. 模型策略的制订
模型策略的制订主要决定模型的组合方式和阈值。在制订相关方案时,我们需要在转化率和坏账率之间进行权衡,以实现最大收益。模型策略应用方案可分为单模型策略和多模型组合策略。
(1)单模型策略
单模型策略是指利用单一模型分进行决策,故只需要确定单一模型的最优决策点。单模型适用场景:
信贷业务开展前期,线上只有一个模型。
信贷业务开展中期,虽然线上模型增多,但是模型间关联性较强,此时,大多以单模型决策为主。
单模型策略的制订决策点设定方式如下:
① 基于模型通过率与坏账率的决策点设定
在模型通过率与坏账率之间寻找一个决策点,理想的状态是该决策点的设立可提高通过率并降低坏账率。而在实际使用过程中,可能出现下列情形。
保持目标模型通过率,降低坏账率。迭代后的新模型上线后,其性能(AUC、KS等指标)通常比线上正在决策的模型好。因此,在信贷业务稳定时,我们可使用此方式,在保证当前通过率的情况下,期望新模型降低坏账率。例如,当前模型通过率为30%,我们可利用近期授信样本集找到通过率30%对应的模型分,并将其作为新模型的决策阈值。
提升模型通过率,保持坏账率。由于不同金融机构所处的发展时期不同,故对业务的诉求会有差异。当金融机构的信贷业务高速发展时,金融机构不一定要降低坏账率,而是需要在保持当前坏账率的同时,提升通过率。例如,当前坏账率为5%,我们需要利用跨时间验证集和近期授信样本集评估得到坏账率为5%时的模型分,并将其作为决策阈值。
提高模型通过率,同时降低坏账率。当新模型的效果较旧模型有大幅提升时,新模型可以同时满足目标通过率和坏账率的需求。此时,我们需要绘制决策曲线,横轴表示模型通过率,纵轴表示坏账率。通过观察决策曲线的走势,我们可以选择合适的决策点。
决策曲线示例如图4所示,当前的决策点在A点时,我们可以选择D点为新决策点,模型通过率和坏账率都会有所优化;如果选择B点为新决策点,即保持模型通过率为40%,那么坏账率将从15%优化到5%;如果选择C点为新决策点,即保持坏账率为
如何制定有效的模型应用策略? 15%,那么模型通过率将从40%提升到60%。
图4 决策曲线示例
② 基于lift的决策点设定
lift表示风控模型对预测目标中不良客户的识别比例高于随机识别比例的倍数。以1为标准,lift小于1表示该模型比随机识别捕捉了更少的不良客户,lift等于1表示该模型的表现等同于随机识别,lift大于1表示该模型比随机识别捕捉了更多的不良客户。在通常情况下,lift的值越大越好。
我们将所有客户的模型评分分为10~20箱,从低到高排序,按分数排序累计至该分箱的不良客户占所有不良客户的比例(Cumulative Bad(%)by model)与随机排序累计至该分段的不良客户占所有不良客户的比例(Cumulative Bad(%)randomly)的比值即lift。图5为实际的lift计算示例,图6为对应的lift提升图。
图5 lift计算示例
图6 lift提升图
通过观察图6,我们可以发现,第一箱(序号0)的lift值为3.13,即该模型预测分数最低的10%客户坏账率是随机识别客户坏账率的3倍多。通过lift的大小,我们可以设定模型的决策阈值。
模型策略本质上是通过科学方法选择模型的最优决策点。上面两种决策点设定方法可以帮助我们快速设定模型决策点并上线应用,但它们主要依靠人的经验,没有考虑到决策阈值对通过率、坏账率和其他成本的多重影响。因此,它们未必是利润达到最大的决策方案。下面将介绍最优化算法在模型策略制订中的应用。
(2)多模型组合策略
多模型组合策略是基于两个或两个以上模型分组合生成的模型应用方案。多模型组合策略的优势如下:
能够充分发挥多个模型性能互补的优势。
内外部模型组合的使用能够有效降低数据成本。
多模型组合策略的应用方式如下:
① 多模型融合准入
多模型融合准入是指利用加权或其他方式将多个模型分融合成一个模型分,再划分风险等级上线决策,如图7所示。从本质上来说,融合后的多模型与单模型是一样的。我们通常采用等频或等距方式对模型分进行划分,一般划分为9个等级(RG1~RG8,RGX),RG1的风险等级最低,RG8的风险等级最高,RG1~RG8表示通过,RGX表示直接拒绝。
图7 多模型融合准入
② 多模型串行准入
多模型串行准入是指将多个模型以串行方式按先后顺序依次决策准入,前一个模型决策通过的样本再经过下一个模型决策进行评估,依此类推,由最后一个模型生成风险等级,如图8所示。
图8 多模型融合准入
在实际业务场景中,多模型串行准入较为常用,适用于多个优势互补的模型分,既有助于多个模型分发挥最大价值,又可节省数据成本。通常,无成本模型先于有成本模型决策。
③多模型交叉准入
多模型交叉准入分为两个阶段:
准入阶段,由前置模型完成。
1.打开路由器
192.168.1.1 依次点击 应用管理->IP与MAC地址绑定
2.输入mac地址和你想这个mac地址绑定的ip,先不管这个mac地址现在的ip,电脑在重启后ip会变成你指定的ip
查看mac地址
3.重启电脑
vue项目中我们请求一个路由,打开页面发现页面是空白的,产生的主要原因有四种:
1.路由重复 如果配置了两个路由是重复的,比如配置了两个【path: ‘/’】,那么访问就会看到空白页面,这时候改下重复的路由配置即可
2.app.js中删除了router-view 我们可以把 app.js看成路由的顶级路由,再创建路由他属于二级路由,依次类推
3.路由导航守卫没有next() 我们写路由导航守卫时,next相当于是安保人员,只有他有权力进行放行,如果他不进行放行,我们肯定无法接着访问,从而导致页面空白
4.访问的就是空白页面 这种情况比较少,我们再访问一个新的页面时,一般会写点文字进行页面展示
1、开启防火墙
systemctl start firewalld
2、开放指定端口
firewall-cmd --zone=public --add-port=1935/tcp --permanent
命令含义:
–zone #作用域
–add-port=1935/tcp #添加端口,格式为:端口/通讯协议
–permanent #永久生效,没有此参数重启后失效
3、重启防火墙
firewall-cmd --reload
4、查看端口号
netstat -ntlp //查看当前所有tcp端口·
netstat -ntulp |grep 1935 //查看所有1935端口使用情况·
今天想测试一下怎么通过一个.py文件写一段多线程代码,把原来的三个flask接口的py文件和成一个,在网上看了很多方法,但都没用上,最后测试时用了最简单的方法,代码如下: from flask import Flask import threading import os from werkzeug.serving import run_simple from werkzeug.middleware.dispatcher import DispatcherMiddleware # ----------服务1----------------- app1 = Flask('app1') @app1.route('/first/') def foo(): print('app1') return '1' # ----------服务2----------------- app2 = Flask('app2') @app2.route('/second/') def bar(): print('app2') return 'hello world' # ----------服务3----------------- app3 = Flask('app3') @app3.route('/third/') def bar(): print('app3') return 'it is the third one' if __name__ == '__main__': # print('main thread is {}'.format(threading.current_thread().name)) # os.environ 返回一个系统变量和系统变量值 的字典(键值对) os.environ["WERKZEUG_RUN_MAIN"] = 'True' threading.
git branch 查看本地所有分支 git status 查看当前状态 git commit 提交 git branch -a 查看所有的分支 git branch -r 查看远程所有分支 git commit -am "init" 提交并且加注释 git remote add origin git@192.168.1.119:ndshow git push origin master 将文件给推到服务器上 git remote show origin 显示远程库origin里的资源 git push origin master:develop git push origin master:hb-dev 将本地库与服务器上的库进行关联 git checkout --track origin/dev 切换到远程dev分支 git branch -D master develop 删除本地库develop git checkout -b dev 建立一个新的本地分支dev git merge origin/dev 将分支dev与当前分支进行合并 git checkout dev 切换到本地dev分支 git remote show 查看远程库 git add .
嗨害大家好鸭,我是小熊猫🖤 最近有很多小伙伴找到本熊猫,
问下面这个报错怎么解决…
selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home 今天,我在这里统一的回复下
代码运行的时候,出现了这个报错是什么意思?但具体该如何解决这个bug呢?
这个报错一般都是第一次学习使用selenium自动化框架的时候出现的,主要的原因是因为selenium模拟的客户端对浏览器的操作,但没有找到相应浏览器的驱动导致的
为了解决这个问题,我们需要先了解我们当前浏览器的版本
首先,你要找到你自己谷歌浏览器的版本 第一种方法 (https://jq.qq.com/?_wv=1027&k=2Q3YTfym)
第二种方法 (https://jq.qq.com/?_wv=1027&k=2Q3YTfym)
右键点击谷歌浏览器,查看属性,复制起始位置
随便找个文件夹粘贴打开你复制的地址
然后你就可以看但你的谷歌浏览器的版本了
如何下载安装浏览器驱动 (https://jq.qq.com/?_wv=1027&k=2Q3YTfym) 百度搜索谷歌浏览器驱动
找到相对应的版本,没有就接近的版本,然后点击下载你想要的版本
将压缩包解压,将chromedriver.exe移动到 Python安装目录下(其实放哪都可以,但是需要配环境变量,放Python安装目录下省事)
这样你以后用selenium自动化框架来操作浏览器的时候,就不会出现提示你没有浏览器驱动的报错了
就是这样啦,不知道有没有帮到你呢? 我是小熊猫,咱下篇文章再见啦(✿◡‿◡)
一、需求 在起前面这篇文章中,ov7725摄像头通过VGA/HDMI显示RGB565格式的图像 完成了用摄像头采集图像后,通过HDMI或者VGA显示图像,现在需要添加一个图像处理模块,对摄像头采集的图像进行处理
但是由于ov7725摄像头使用的是GRB565格式的图像,但是在图像处理中使用的是RGB888的图像格式,于是就需要将GRB565转为RGB888
二、什么是GRB565、RGB888 RGB888:红绿蓝各占8位,共24位信息
GRB565:red[15:11]、green[10:5]、blue[4:0] 这几位分别取8位红绿蓝的高位
那GRB565比RGB888少了8位数据,少的这几位都是3中颜色的地位数据,即用来表示背景颜色的数据被丢失了
三、如何实现 如下,用了RGB565的地位补全信息
.per_img_red ({vga_rgb[15:11], vga_rgb[13:11]}), .per_img_green({vga_rgb[10:5], vga_rgb[6:5]}), .per_img_blue ({vga_rgb[4:0], vga_rgb[2:0]}), 四、其他格式转换 推荐阅读:看最后的附录
4.1 8位灰度Y - 转 - 16位数据 在往摄像头显示的工程中加入图像处理算法:图像处理1:RGB888_YCbCr444 时用到了
assign data_out = {post_img_Y[7:3],post_img_Y[7:2],post_img_Y[7:3]};
JS(javascript)面试题 提示:JS(javascript)面试题 => 必会之八股文 目录索引查看
面试题 JS(javascript)面试题@[TOC](面试题) 一、原型 和 原型链二、防抖 与 节流1.防抖2.节流 三、闭包1.为什么不要定义全局变量? 四、null 和 undefined五、filter 的使用六、forEach() 和 map()forEach()map() 七、var let 和 constvarletconst 提示:以下是本篇文章正文内容,下面案例可供参考
一、原型 和 原型链 prototype (原型) => 原型是函数所特有的
__ proto __ => [[ prototype ]] (原型链)
对象原型( _ proto _ )指向它的构造函数的原型对象(prototype),原型对象再次指向上一层的对象原型,直至指向的原型对象为 null 或是指向 object 的原型对象(null)。null没有原型,原型链到此结束。
提示:当继承的函数被调用时,this 指向的是当前继承的对象,而不是继承的函数所在的原型对象。
function Foo(uname,age) { this.uname = uname; this.age = age; } function Son(uname,age,score) { Foo.call(this,uname,age); this.score = score; } Son.prototype = new Foo();//Son.
使用proxy解决跨域问题 问题引入
前端如果不通过proxy设置代理,则请求接口会报跨域问题
Access to XMLHttpRequest at 'https://www.baidu.com/s?ie=utf+-+8&mod=1&isbd=1&isid=28B087E526051712&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=this.$axios&fenlei=256&oq=this.%2524axios&rsv_pq=af3009be00003a79&rsv_t=1c5fWtMk%2B6xwWKQqibPt6DyyGzLEaQSdASvH93Q6UDEXyZdfGTnRxojuNms&rqlang=cn&rsv_enter=0&rsv_dl=tb&rsv_btype=t&bs=this.$axios&_ss=1&clist=&hsug=&f4s=1&csor=' from origin 'http://172.16.20.231:8080' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
解决方案
1.在vue.config.ts中进行配置 //vue-cli3.0 里面的 vue.config.js做配置 devServer: { proxy: { '/cdn': { target: 'https://position.csdnimg.cn', // 后台接口域名 ws: true, //如果要代理 websockets,配置这个参数 secure: false, // 如果是https接口,需要配置这个参数 changeOrigin: true, //是否跨域 pathRewrite:{ '^/cdn': '/' } } } } 2.在具体页面发送请求 假设要请求的后端地址为’https://position.csdnimg.cn/oapi/get’
//使用axios进行请求,首先在main.ts中将axios挂载到vue原型中 import axios from 'axios' Vue.prototype.$service = axios //在具体页面中使用this.
写在前面的话
本期和大家分享一个开源的项目,我是在人人开源项目的基础上修改了部分代码,供大家使用,它可以自动根据你的表需求生成相应的代码(包括 model实体类 service业务层 Dao数据库层 Controller层 以及Mapper.xml文件)
下面具体来分析下这个项目:
首选项目开源地址: 项目地址
download下载地址: 下载地址
在使用这个项目的时候,可以根据自己的需求配置数据库,如果你使用的mysql,可以在application.yml配置文件中找到auto.database配置
#指定数据库,可选值有【mysql、oracle、sqlserver、postgresql、mongodb】 auto: database: mysql 根据实际需求更改,如果你要导出mongo的表数据 ,可以将配置更改为
auto: database: mongodb 另外 可以根据需要对数据库表的数据类型和Java实体对象类型之间的转换,可以修改generator.properties配置,下面给出部分配置
#配置路径 mainPath=com.fairy.cloud #生成的项目包路径 package=com.fairy.cloud #项目模块名称 moduleName=mbg #\u4F5C\u8005 author=鹿少年 #Email email= #表的前缀 tablePrefix= #数据库字段类和java 字段类型转换 tinyint=Integer smallint=Integer mediumint=Integer int=Integer integer=Integer bigint=Long float=Float double=Double decimal=BigDecimal bit=Boolean char=String varchar=String tinytext=String text=String mediumtext=String longtext=String 根据自己的需要来配置,下面大家就快去下载项目到本地,一起感受下
<avue-crud :option="option" ref="crud" //表格常用事件 @on-load="getList"//这个事件会在表格所在的组件加载时就会执行后面的getList方法,初始化表格数据。并且当表格翻页或者pageSize变化时候也会自动执行该方法,这时候表格绑定的 :page.sync="page"中的page的值也会随时更新,当页面大小变化时,还会自己将页面变为1 如果使用了这个方法 其实表格的 @current-change @size-change两个事件处理函数就不需要了 翻页事件全在on-load里面处理了 @current-change="事件处理函数"//表格翻页的页码发生变化时,并且事件处理函数里面第一个参数就是翻页的页码 @size-change="pageSizeChange"//表格翻页每页显示条数变化时触发,并且事件处理函数里面第一个参数就是当前的size大小 @search-change="searchChange"//表格搜索 事件处理函数默认有两个参数 form与done 第一个为搜索框的值 第二个为关闭搜索的刷新状态 @row-save="rowSave"//表格新增表单确定按钮的回调,注意:事件处理函数rowSave默认有三个参数分别为:row,done,loading,row是表单的值,done用于关闭表单 @row-update="rowUpdate" //表格行编辑的回调,改事件处理含数默认四个参数 row,index,done,loading @row-del="rowDel"//表格操作行删除按钮回调,事件处理函数接受两个参数,row,index 。row是表单数据,index是当前数据所在表格行的索引 @refresh-change="refreshChange" //表格的刷新按钮的回调,这个函数默认自己不带参数 @current-row-change="handleCurrentRowChange"//表格行被点击时的回调,回调函数的第一个参数是当前被点击行的数据 @tree-load="treeLoad"//表格行展开的懒加载回调,回调函数自带三个参数 row, treeNode,resolve row:当前展开行的数据 treeNode:展开行节点数据 resolve:行懒加载的成功回调,在resolve里面将懒加载的数据传出去表格进行渲染 回调函数大致写法如下: // 表格展开懒加载回调 treeLoad(row, treeNode,resolve) { this.tjjcode = row.code //重新调用getStatData方法获取数据,在resolve里面将新数据传递出去供表格渲染子节点 getStatData(this.deptId.id,this.tjjcode).then(res=> { let list = res.data.data; resolve(list); }); }, > </avue-crud> //表格option配置 option:{ title:'表格的标题', :table-loading = "tableLoading"//表格的状态(刷新、非刷新) align:'center', // 表格列齐方式 menuAlign:'center', // 菜单栏对齐方式 excelBtn: true,//表单导出按钮 columnBtn:false, //列动态显隐按钮 refreshBtn:false, // 刷新按钮 saveBtn:false, // 新增表单的保存按钮; updateBtn:false, // 更新按钮 emptyBtn:false//搜索清空按钮 addBtn:false, // 表格新增按钮 expand: true//设置表格行可展开 注意:一般懒加载开启就不设置expand为true expand:true会在表格第一列前面自己加一列放展开箭头类似于序号列那样 不加的话不会多产生一列 就在数据第一列有一个下拉箭头 样式稍微美观一点 所以一般不加 expand:true的设置 lazy:true,//开启行展开懒加载 rowKey:'code',// 表格行可展开的key 表格行展开必须设置rowKey accordion:true,//同级节点只展开一个 另外的收起 menu: false,//表格操作列关闭、开启(查看 编辑.
volatile关键字和CAS总结
一、volatile关键字
1.1 volatile的理解
1.2 JMM内存模型之可见性
1.3 volatile不保证原子性
1.4 volatile禁止指令重排
1.5 volatile的应用(单例模式DCL代码)
二、CAS
2.1 CAS是什么
2.2 CAS底层原理
2.3 CAS缺点
2.4 ABA问题
2.4.1 AtomicReference原子引用
2.4.2 AtomicStampedReference版本号原子引用(ABA问题的解决)
-JUC
-多线程 JUC(java.util.concurrent) - 进程和线程 - 进程:后台运行的程序(我们打开的一个软件,就是进程) - 线程:轻量级的进程,并且一个进程包含多个线程(同在一个软件内,同时运行窗口,就是线程) - 并发和并行 - 并发:同时访问某个东西,就是并发 - 并行:一起做某些事情,就是并行 - JUC下的三个包 - java.util.concurrent - java.util.concurrent.atomic - java.util.concurrent.locks 一篇文章搞懂java内存模型、JMM三大特征、volatile关键字
1.1 volatile的理解 Volatile是Java虚拟机提供的轻量级的同步机制(三大特性) - 保证可见性 - 不保证原子性 - 禁止指令重排 1.2 JMM内存模型之可见性 JMM的三大特性,volatile只保证了两个,即可见性和有序性,不满足原子性
JMM是Java内存模型,也就是Java Memory Model,简称JMM,本身是一种抽象的概念,实际上并不存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式
JMM关于同步的规定:
线程解锁前,必须把共享变量的值刷新回主内存线程加锁前,必须读取主内存的最新值,到自己的工作内存加锁和解锁是同一把锁 由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方称为栈空间),工作内存是每个线程的私有数据区域,而Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝到自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,各个线程中的工作内存中存储着主内存中的变量副本拷贝,因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成,其简要访问过程:
数据传输速率:硬盘 < 内存 < < cache < CPU
概述 工厂方法模式 | 偷掉月亮 (moonshuo.cn)
原文链接:抽象工厂模式 | 偷掉月亮 (moonshuo.cn)
抽象工厂模式:提供一个创建一系列相关或者相互依赖的对象的接口,而无需指定他们的类
工厂三兄弟之抽象工厂模式(二)_LoveLion的博客-CSDN博客
对于上述的产品构造,如果我们采用工厂方法模式,那么我们需要实现15个工厂方法,但是我们可以发现对于这个来说,我们可以合并一个产品族,即一个工厂内部可以生产一次性生产深色的方形,圆形,椭圆,那么我们现在只需要有5个工厂方法
实例 对于下面的产品来说,海尔家族是一个产品组,海信是一个产品组,康佳是一个产品组,每一家都可以生产空调,电视,冰箱
这里就不适用反射进行操作了,如果想要看反射的操作(类似spring操作),看工厂方法模式 | 偷掉月亮 (moonshuo.cn)
首先两种产品
电视:
package 设计模式.抽象工厂模式.产品; /** * @author zss * @date 2022-08-02 14:21:41 * @description 电视的抽象类 */ public interface Television { /**生产产品的方法*/ void manufacturePro(); } 海尔电视:
package 设计模式.抽象工厂模式.产品.海尔家族; import 设计模式.抽象工厂模式.产品.Television; /** * @author zss * @date 2022-08-02 14:23:21 * @description 海尔电视生产方式 */ public class HaierTV implements Television { @Override public void manufacturePro() { System.
Office一代更新一代,想不想了解Office图标的发展历程?今天就给大家列举一下,看一看你都用过哪一版?
1. 2016版
发布于2015年的Office 2016,延续了13版设计风格,只是在其基础上做了一点点小幅优化,看起来更加明显。其实这个版本也是很多网友在用的版本,同时也是非Win10系统能够安装的最高版本。
Office 2016版图标
官网链接:Office 2016 家庭和学生版 办公软件
2. 2019版(最新)
最新版Office 2019和Office 365使用了新图标,整体风格简约大气,融合了微立体、渐变色等很多时下流行元素,再配合Windows 10的Light Theme更显逼格满满。不过Office 2019需要Win10系统才能安装,这就使得很多用户其实是无缘最新版的。那么当Office开始置换新装时,你是否愿意试一试呢?
最新版Office 2019版图标
2. 2019版(早期)
Office 2019最早发布于2018年,初代使用Office 2016的图标设计,这套图标其实早在2013年即开始定型, 16版则对它进行了小幅改动。虽然也是扁平化设计,但历时7年时间,早已让这套图标倍显老气。2018年底,微软宣布将更新Office图标,Office开始走上新路途。
官网链接: Office 2019 家庭和学生版 办公软件
Office 2019 Professional 专业增强版 办公软件
office2021改进 1、office2021官方正式版提供了更好的工作环境。
2、拥有更好的表格设计能力。
3、在新版的Excel软件上增加了更好的计算功能。
4、可以在添加函数的时候提供更好的插入方式。
5、内置的函数更加丰富,计算 过程更轻松。
6、对于制作数据模型也是很好用的。
7、office2021在设计PPT方面也更新多种功能。
8、提供了更好的图标设计方案。
9、支持更好的UI界面,滚动查看PPT效果更好。
10、在设计PPT的时候提供了在线插入图标的功能。
11、也提供了一个图标库,方便您轻松插入需要的图标。
12、Word的新版功能也是很多的。
13、提供了界面色彩调整功能,编辑Word效果更好。
14、提供了新的“沉浸式学习模式”。
15、排版文章功能更好,调整文字间距、页面幅度等更好。
16、另外新版的Word也是可以将文章朗读的。
17、增加了新的shoppingmode 微软语音引擎,轻松将文字转换语音。
官网链接:
Office 2021 家庭和学生版 办公软件
office2021新特性 大为改善的操作界面:Office2021对操作界面作出了极大的改进,将Office2021文件打开起始时的3D带状图像取消了,增加了大片的单一的图像。Office2021的改善并仅做了一些浅表的工作。其中的“文件选项卡”已经是一种的新的面貌,用户们操作起来更加高效。例如,当用户想创建一个新的文档,他就能看到许多可用模板的预览图像。
PDF文档完全编辑:PDF文档实在令人头疼,说它令人头疼是因为这种文档在工作中使用有诸多不便。即使用户想从PDF文档中截取一些格式化或非格式化的文本都令人抓狂。不过有新版的Office2021套件,这种问题将不再是问题了。套件中的Word能够打开PDF类型的文件,并且用户能够随心所欲地对其进行编辑。可以以PDF文件保存修改之后的结果或者以Word支持的任何文件类型进行保存。
自动创建书签:这是一项Office2021新增的功能,对于那些与篇幅巨大的Word文档打交道的人而言,这无疑会提高他们的工作效率。用户可以直接定位到上一次工作或者浏览的页面,无需拖动“滚动条”。
内置图像搜索功能:在网络上搜索出图片然后插入到PowerPoint演示文稿中并不轻松。shoppingmode 微软也考虑到了用户这方面的需求,用户只需在Office2021中就能使用必应搜索找到合适的图片,然后将其插入到任何Office文档中。
Excel 快速分析工具:对于大多数用户而言,用好的方法来分析数据和呈现出数据一直是一个令人头疼的问题。Office2021有了Excel快速分析工具,这问题就变得简单多了,用户输入数据后,Excel将会提供一些建议来更好地格式化、分析以及呈现出数据等等。即使是一些资深Excel用户都会非常喜欢这一功能。
从网上下载到资源文件后,为了确保下载的文件没有被黑客非法篡改,一般都会校验一下MD5是否与最初上传的版本是否一致。查看两个文件的MD5 值可以判断文件在传输过程中有没有损坏,或者丢失字节。
Windows电脑 window(键盘左下角Ctrl右边的按键)+R 快捷键输入cmd后回车,查看文件的MD5: 在命令行中使用 certutil -hashfile [文件路径] MD5命令,示例如下:
$ certutil -hashfile C:\Users\hsns\Desktop\BCM20702A.hcd md5 执行结果如下图,da0c223aaacf40ce8b61d0fb18a29e1c 就是MD5值
adb shell进入安卓系统里查看文件的 MD5值: 在命令行中使用 md5sum [文件路径],示例如下
md5sum device/BCM20702A.hcd 执行结果如下图,da0c223aaacf40ce8b61d0fb18a29e1c 就是MD5值
参考文章:https://www.jianshu.com/p/431fc37abb6f
【简介】我们已经知道了可以在策略里指定某些IP允许上网,也可以指定某些IP禁止上网,但是如果某个员工知道了某个IP是可以上网的,把他自己的电脑改成这个IP,那不是也能上网了?为了防止修改IP地址后可以上网,我们需要将IP地址与网卡的MAC地址绑定在一起,这样即使修改了IP地址,但MAC地址不符,也是不能上网的。
接口环境
防火墙的内网接口常见的有硬件交换和各自独立两种,我们以各自独立的接口为例。
① 这里配置内网接口5,IP地址为172.20.5.1,打开了DHCP服务,允许自动分配IP地址。
② 在这个接口只允许部分IP地址上网,因此建立一个地址对象,指定可以上网的IP地址范围。
③ 建立上网策略,指定172.20.5.180-172.20.5.200这个IP范围的电脑,可以通过Wan1接口上网。
④ 在internal5接口上接上电脑,自动获取IP地址,根据DHCP服务的启始IP,获得的IP地址是172.20.5.20,但在策略里只允许180-200可以上网,因此这台电脑是不能上网的。
⑤ 手动将电脑IP地址修改为172.20.5.188,符合上网地址范围180-200,因此可以看到,这个IP地址的电脑是可以上网的。
MAC 地址占用
手动修改IP地址允许上网,很显然会工作量比较大并且效率低,其实我们只要记录下允许上网电脑的网卡MAC地址,将MAC地址与可以上网的IP地址绑定,就可以轻松达到目的了。
① 在网卡的属性中,我们可以看到网卡的物理地址,也就是MAC地址。
② 选择菜单【网络】-【接口】,选择internal5接口,点击【编辑】,可以看到接口内容,点击DHCP服务器设置里的高级选项。
③ 在MAC占用+访问控制设置中,点击【新建】,将MAC地址与IP地址填入,动作为保留IP。可以建立多条MAC占用。点击【确认】。
④ 修改网卡的配置为自动获取IP地址与DNS。
⑤ 获取IP后可以看到,这个MAC地址得到的IP是指定172.20.5.188,而不再是一开始获得的172.20.5.20了。这样就可以通过策略允许上网了。
⑥ 这样操作虽然很省心,但也不是没有漏洞。如果正好这台电脑关机了,我们用另一台电脑手动修改地址为172.20.5.188,还是可以上网的。也就是说,DHCP里的设置只是占用了IP地址,并没有绑定在一起。
MAC地址绑定表
实际上,防火墙象设置黑白名单一样,可以设置一张MAC地址绑定表,并允许通过绑定表控制是否能访问防火墙或外网。只是这张绑定表的配置都需要通过命令来完成。
① 在仪表板上有可以输入命令的CLI控制台,也可以随时通过右上角的子菜单点击CLI Console打来命令输入窗口。
② 输入get firewall ipmacbinding table命令,可以看到MAC地址绑定表的内容,默认是空的。
③ 配置MAC绑定表的命令是config firewall ipmacbinding table,表格的内容包括序号、IP地址、MAC地址、备注(可选)、状态。
④ 根据MAC绑定表的结构,我们收集了三个MAC地址信息,分别是无线路由器外网接口、直连防火墙的电脑MAC地址,还有连接三层交换机再经过防火墙的电脑MAC地址。分别测试不同环境下的绑定效果。
⑤ 用config firewall ipmacbinding table命令进入配置状态,edit 0表示从最后一个开始加入表,例如是空表,edit 0就表示编辑第1个,如果里面有5条记录,edit 0就表示编辑第6条。next表示完成这条编辑,end保存并退出。
⑥ 用show firewall ipmacbinding table命令可以看到刚已经建立的三条记录,并自动编写了序号。
⑦ 如果需要修改某条记录,进入配置状态后,编辑记录序号,设置修改内容,end退出保存。例如修改状态,使某条记录启动或禁用MAC绑定。
⑧ 对于确定不再使用的记录,也可以用delete命令加序号删除。
【提示】 如果需要绑定几十至几百条MAC地址,手动一条条输入确实很影响效率,可以参考:维护篇(5.2)-08. 批量命令操作 ❀ 飞塔 (Fortinet) 防火墙。
目录
一、前言 根据多篇文章总结了一下自己操作过程,主要是想记录一下。
二、版本 1.查看自己的Firefox的版本,在浏览器右上角的三条横线中,帮助—>关于Firefox
 2.选择与自己对应的selenium驱动,我的Firefox是最新的版本,我也不是很清楚选择什么版本,下载了最新的geckodriver,成功的驱动了Firefox。
驱动下载地址: https://github.com/mozilla/geckodriver/releases/
三、配置环境 1.将下载好的geckodriver放到Firefox的根目录中
2.配置环境变量
按快捷键win+R,输入“sysdm.cpl”,回车 选择高级,进入环境变量,找到path双击进入。
将下载的geckivodrer文件路径复制并粘贴到新建中 完成配置
四、在pycharm中添加selenium 1.File—>settings,点击小框中左上角的“+”,查找selenium
点击Install Package
五、测试代码,成功打开百度,则配置成功 from selenium import webdriver driver = webdriver.Firefox() driver.get("http://www.baidu.com") driver.find_element_by_id("kw").send_keys("python")#定位百度的输入框,输入python driver.find_element_by_id("su").click() 呆瓜半小时入门数据分析
导读:在数字化时代的大背景下,在数据驱动的产品增长理论和实践中,AB实验起的作用越来越重要。越来越多的岗位需要产品、运营、数据等职位候选人掌握AB实验相关的知识。
作者:刘玉凤
来源:华章计算机(hzbook_jsj)
本文首先介绍AB实验的基本概念和原理,然后介绍AB实验的3个基本要素—实验参与单元、实验控制参数、实验指标,以及对于这3个基本要素的要求,之后介绍AB实验的2个核心价值——验证因果关系和量化策略效果,接着介绍在实践应用中AB实验的2个关键特——先验性和并行性。
01
什么是AB实验
近几年随着增长概念的普及,其重要增长手段——AB实验的曝光度也越来越高。AB实验从推荐系统诞生开始,AB实验就扮演着重要的角色
1
AB实验的定义
AB实验又称为受控实验(Controlled Experiment)或者对照实验。AB实验的概念来自生物医学的双盲测试,双盲测试中病人被随机分成两组,在不知情的情况下分别给予安慰剂和测试用药,经过一段时间的实验后,比较这两组病人的表现是否具有显著的差异,从而确定测试用药是否有效。
2000年,Google工程师将这一方法应用在互联网产品测试中,此后AB实验变得越来越重要,逐渐成为互联网产品运营迭代科学化、数据驱动增长的重要手段。从国外的Apple、Airbnb、Amazon、Facebook、Google、LinkedIn、Microsoft、Uber等公司,到国内的百度、阿里、腾讯、滴滴、字节跳动、美团等公司,在各种终端(网站、PC应用程序、移动应用程序、电子邮件等)上运行着大量的AB实验。这些公司每年进行数千到数万次实验,涉及上亿的用户,测试内容涵盖了绝大多数产品特征的优化,包括用户体验(颜色、字体和交互等)、算法优化(搜索、广告、个性化、推荐等)、产品性能(响应速度、吞吐量、稳定性、延迟)、内容(商品、资讯、服务)生态管理系统、商业化收入等。
因为AB实验被引入互联网公司后,应用场景主要是大规模的在线测试,所以也被称作在线AB实验或者在线对照实验(Online Controlled Experiment,OCE)。本文如果没有特殊说明,提到的AB实验均指在线AB实验。常见的在线AB实验中,用户被随机、均匀地分为不同的组,同一组内的用户在实验期间使用相同的策略,不同组的用户使用相同或不同的策略。同时,日志系统根据实验系统为用户打标记,用于记录用户的行为,然后数据计算系统根据带有实验标记的日志计算用户的各种实验数据指标。实验者通过这些指标去理解和分析不同的策略对用户起了什么样的作用,是否符合实验预先的假设。如图1所示,图中流程概括了AB实验的经典模式。
图1 AB实验流程
将图1所示的流程应用到产品迭代中,就是将具有不同功能、不同策略的产品版本,在同一时间,分别让两个或多个用户组访问。这些参与实验的用户组是从总体用户中随机抽样出来的,一般只占总体用户的一小部分,而且不同组用户的属性、构成成分是相同或相似的。先通过日志系统、业务系统收集各组用户的行为数据和业务数据,然后基于这些数据指标分析、评估出相比之下更好的产品版本,最后推广到全部用户。
以图2为例,我们试图通过AB实验找出哪个颜色的横幅位点击率更高:A组保持浅色横幅不变,B组采用深色的横幅,分析哪个颜色更能引起用户的关注,提升用户的点击率。如果通过实验发现深色横幅的点击率更高,就将深色横幅位推广到全部用户。当然,在实际应用中,AB实验的效果评估一般没有这么简单,比如除了点击率之外,还需要综合考虑其他的指标。
图2 AB实验测试哪个颜色横幅位点击率更高
2
AB实验的类型
从不同分类视角来看,AB实验有着不同的类型。
从实验实施的产品形态来看,AB实验可以分为App类型、PC类型、网页页面类型等。
从实验代码运行的机制来看,AB实验可以分为前端页面类型、后端服务类型等
从实验分流的对象来看,AB实验可以分为用户类型、会话类型、页面类型、元素类型等。
从实验服务调用的方式来看,AB实验可以分为SDK类型、接口服务类型等。
从实验内容来看,AB实验可以分为交互类、算法类、内容类、工程性能类等。
这些是AB实验常见的分类方式。当然,AB实验的分类不局限于以上分类,可以根据实际情况,采用不同的分类方式。不管何种类型的AB实验,都应符合分流→实验→数据分析→决策的基本流程,以及需要满足AB实验的3个基本要素。
02
AB实验的3个基本要素
AB实验虽然能帮助我们更科学地做出决策,但并不能科学地辅助所有决策,这是因为不是任何一件事情都可以进行AB实验,下面将详细介绍进行AB实验首先需要具备的基本要素。
1
实验参与单元
进行AB实验首先必须要有能够参与实验的对象,即实验参与单元,一般来说就是能参与实验的用户。在AB实验中,把参与实验的用户分为两组或者多组,其中至少有一组作为对照组,对照组用户什么都不改变,作为对比实验效果的基线;其余组为实验组,实验组可以进行各种产品特征实验。想要确保实验的科学性,参与用户还需要满足几个关键条件。
1)实验参与单元互不干扰
实验参与单元(例如实验用户)被分配到不同的实验组,需要确保不同的实验参与单元互相不干扰或者干扰小到可以忽略。如果不同实验组之间的实验参与单元相互影响,那么就会影响实验结果的正确评估。
2)实验参与单元合理随机化
实验参与单元随机化就是将随机化过程应用于实验参与单元,以实现将它们分到不同的实验组的目的。科学随机化非常重要,需要确保分配给不同实验组的实验参与单元在统计学上是相似的,从而以较高概率确定因果关系。在随机化的过程中,必须以持久且独立的方式将实验参与单元映射到实验组。持久的意思是,实验参与单元在整个实验期间不得改变分组。为了保证实验效果,实验参与单元将不被告知任何实验相关的信息。实验参与单元最好对于实验信息无感知,否则会对实验造成干扰。
不要对随机化掉以轻心,在实践中,存在很多失败的随机化例子,都说明了科学随机化的重要性和面临的挑战。造成随机过程失败的原因多种多样,简单来说,就是随机过程变得不随机了,使得在实验前不应存在统计学差异的实验组和对照组出现显著差异,出现了实验影响以外的影响因素干扰实验结果。我们将在第5章详细讨论实验随机分流的问题。
3)足够的实验参与单元
根据统计学的理论,AB实验的实验参与单元需要达到一定数量,统计指标才是有意义的(相关统计知识在《AB实验:科学归因与增长的利器》第3章介绍)。特别是在进行一些指标提升幅度不是很大的实验时,实验参与单元的数量尤其重要。一般来说,实验实际提升效果越不明显,就越需要更多的参与单元来确认实验效果。同理,实验参与单元的数量越多,实验就可以检测出越小的效果变化,检测的精度也就越高。
以内容行业的AB实验经验来说,对于点击量、曝光量等变化幅度较大的指标,检测出1%的指标相对变化,往往需要十万级以上的实验参与单元;对于留存率这类变化幅度较小的指标,检测出1%的指标相对变化,需要更多的实验参与单元。如果实验参与单元数量不够,比如一些初创、垂类的产品,用户只有几千或几万个,这个时候通过AB实验检测出的变化是粗粒度的,可能只能有效检测出3%、5%甚至10%以上相对幅值的实验效果。
从直观上也不难理解,用户越少,指标本身的变化和波动就越大,我们往往难以判断一个实验组和对照组之间的小幅度差异是天然的随机波动还是实验带来的效果。如果这个差异值足够大,大到超出了一般的波动范围,那么这个差异是实验带来的可能性就高一些。对于小用户体量的产品来说,预期提升很小的指标一般不建议进行AB实验。如果一个优化策略能够带来很大的提升,那么用较少的用户量也是可以检测出的。
处于初创期的产品往往能够通过渠道放量、用户增长等方式快速获得更多用户,从而逐步具备进行更加精准的AB实验的条件。随着用户规模的增加以及业务发展的日趋成熟,检测较小的变化变得越来越重要。例如,像亚马逊这样的大型网站,某指标0.5%的增长带来的收益可能就是上亿美元。不同阶段的产品、不同数量级的实验单元都可以做AB实验,关键是实验参与单元数量要达到满足实验检测当前业务变化所需的精度,并将实验结果误差控制在可接受的范围。如何找到合适的实验单元量以及业务评估精度,在《AB实验:科学归因与增长的利器》4.3节会详细介绍。
2
实验控制参数
实验控制参数是影响产品某项指标的可控实验变量,也被称为因子或变量。简单来说,就是实验策略中不同的赋值,比如横幅栏颜色实验中,控制参数就是颜色,实验组控制参数的赋值为红色,对照组赋值为蓝色。实验控制参数也需要满足一些条件方可进行AB实验。
1)实验控制参数可分配
在简单的AB实验中,通常只有一个参数,这个参数有两个赋值或者多个赋值。在在线实验中,通常使用多变量设计。一起评估多个变量的实验,称为多变量实验(Multi-Variable Test,MVT),比如同时评估字体颜色和字体大小,允许实验者在参数交叉时发现全局最优值。
在简单的AB实验中,一般将实验参与单元随机分为实验组和对照组。控制参数也就对应地分配给实验组和对照组。例如,某App的字体大小是一个控制参数,这个参数可以有10号、12号等不同的值。我们将不同的值赋予不同的组别,比如实验组10号,对照组12号,这两组除了字体的差异外无其他差异,这样就可以通过实验数据对比出10号、12号字体在使用过程中对产品指标的影响。
控制参数可分配是实验可以顺利进行的最关键因素,如果不可分配就没法进行AB实验,只能借助其他方法进行判断和决策。
2)实验控制参数容易改变
做AB实验需要控制参数容易改变,如果改变控制参数很困难,实验成本就非常高。一般来说,软件通常比硬件更容易更改。然而某些软件领域也需要一定级别的质量保证,比如飞机飞行控制系统软件的更改就需要航空管理局的批准。服务器端软件比客户端软件更容易更改,这是因为客户端软件的改变一般需要版本发布之后才能完成。对于那些不升级版本的用户,新实验特性就无法触达了。大部分情况只有80%~90%的用户会完成升级,一部分老用户甚至一直停留在旧版本。版本升级是一个缓慢的过程,一般App至少需要1~2周来完成这个升级。此外,现在产品迭代速度非常快,很多App在1~2周,最多1个月内,就会发布一个新版本。很可能老版本的升级还没有全部完成,又有新版本发布,用户一直处于动态变化的过程中,这种不稳定的状态对于检测实验效果存在一定干扰。现在也有一些新技术使得应用程序可以在后端改变前端的展示效果,使得服务的升级和更改能够迅速完成。
3
实验指标
实验指标是用于评估实验结果的各项指标数据。从实验评估效果的角度来看,需要实验指标满足两个基本要求。
1)实验指标能反映实验者的意图
因为实验的效果主要是通过实验指标来判断的,所以对于实验指标的一个基本要求就是,实验指标要能反映实验者的意图。如何理解这句话呢?在线实验中,主要通过用户在产品上的行为来收集数据,这个方式最大的优势是不需要用户做出额外的动作,包括提交问卷等,而只是完全真实地记录用户行为而已。这种不被用户感知的方式,相比于与用户访谈等方式,能更加真实地反映用户行为。
这种数据收集方式带来了一个问题,就是行为数据不能直接反映用户行为的原因。比如,一个用户最近访问次数减少了,或者一个用户一段时间后流失了,这背后的原因可能是产品本身导致的,也可能是受外部因素影响的。从行为数据上是没有办法直接得到答案的,我们只能通过一些行为数据去推测原因,这样的推测也只是一个可能的概率,没有办法得到完全的证实。建立我们关心的产品问题和这些行为数据之间的关联,本质上就是寻找指标的指向性,在《AB实验:科学归因与增长的利器》一书11.2节会详细讨论指向性。
2)实验指标可测、易测
实验指标是评估实验的关键,如果想观察的实验结果无法容易且准确地获得评估指标数据,即使我们进行了实验,也没有办法评估实验结果。在真实环境的测试中,用户的反馈是很难获得的。虽然可以通过电话、邮件或者访谈等方式获得用户反馈,但这些都不能完全反映用户的真实想法。在软件领域,这些实验数据相对容易获得,其他领域的实验数据可能就困难多了。比如,一些社会学类的实验和药物类的实验所需要的数据,可能都需要人工一个个去采集。
有了可采集的实验数据以及相应的实验指标后,另一个关键问题就是需要实验关键指标已达成一致,并且可以实际评估。如果目标太难衡量,那么替代指标达成一致就尤为重要了,这便是在《AB实验:科学归因与增长的利器》一书11.3节将谈到的OEC。
03
AB实验的2个核心价值
本节主要介绍在实验效果评估中,AB实验的2个核心价值:定性因果和定量增长。
1
文章目录 一、使用工具Navicat for MySQL导入 1.打开localhost_3306,选中右击“新建数据库”2.指定数据库名和字符集(可根据sql文件的字符集类型自行选择)3.选中数据库下的表运行SQL文件4.选中路径导入 二、使用官方工具MySQL Workbench导入 1、第一种方法 ①.新建一个数据库demo(名字任取),点击指示图标(或者File栏里面的Open SQL Script…)②.选中路径导入SQL文件③.添加指定库名的命令 ,并点击运行 注意:大概在15、16行的位置,如果不添加,则导入无效 ④.刷新查看结果 2、第二种方法 ①.点击导入(或者Server栏里Data Import)②.选择导入文件的路径③.Start Import④.刷新查看结果 三、使用命令行导入 1.点击开始菜单输入cmd回车,打开dos界面;2.cd进入到MySQL安装目录的bin文件下;3.输入“mysql -u root -p”,再输入数据库密码;4.create database Demo新建一个库;5.选中数据库use Demo;选中导入路径source D:Demo.sql;6.查看表show tables; 总结 一、使用工具Navicat for MySQL导入 工具的具体下载及使用方法推荐博客园的一篇文章: https://www.cnblogs.com/chyf1990/p/12987101.html
1.打开localhost_3306,选中右击“新建数据库” 2.指定数据库名和字符集(可根据sql文件的字符集类型自行选择) 3.选中数据库下的表运行SQL文件 4.选中路径导入 二、使用官方工具MySQL Workbench导入 1、第一种方法 ①.新建一个数据库demo(名字任取),点击指示图标(或者File栏里面的Open SQL Script…) ②.选中路径导入SQL文件 ③.添加指定库名的命令 ,并点击运行 注意:大概在15、16行的位置,如果不添加,则导入无效 PS:不用点保存,导入后直接×掉即可,保存会修改sql文件本身;
④.刷新查看结果 2、第二种方法 ①.点击导入(或者Server栏里Data Import) ②.选择导入文件的路径 ③.Start Import ④.刷新查看结果 三、使用命令行导入 1.点击开始菜单输入cmd回车,打开dos界面; 2.cd进入到MySQL安装目录的bin文件下; 3.输入“mysql -u root -p”,再输入数据库密码; 4.create database Demo新建一个库; 5.选中数据库use Demo;选中导入路径source D:Demo.
排队 排队是日常生活中经常遇到的事情,如超市结账,餐厅就餐等。有时候,因为队伍实在是太长,或者比较着急,排队过程中经常会遇到插队的情况。
允许插队时,一个人到达餐厅时会先看看队列里面是否有熟人,如果发现了熟人,他就会插队并排到熟人的后面。如果没有熟人在排队,他就只能在队尾排队。有时候,队伍中的某个或某些相熟的同学实在不想排队了,他们就会离队。队伍中的人只有在轮到自己时,才会办理业务并离队。
小A正在研究允许插队的排队问题,他准备编写一个计算机程序,模拟排队的过程。他把相熟的人定义为若干小组,每个小组中的人都是相熟的,相熟的人排队时会插队。在此基础上,他定义了一系列指令,表示排队过程中发生的情况。
enqueue x: x开始排队;dequeue: 队头的人办理完业务离队;deqteam x:x及相熟的人(若存在)离队;stop:停止模拟; 输入 输入数据有若干组,每组为的第一行为一个整数gg,表示一共有多少个小组。随后的gg行中,每行表示一个小组。小组行的最前面为一个整数nn,表示小组中有nn个人,随后有空格分隔的nn个名单,每个名字最长不超过10个字符,由大小写字母或数字构成。随后的若干行为排队模拟指令,stop指令表示该组数据结束。
输出 对每组测试数据,在第一行输出一个Case #k:,k为测试数据的组号,从1开始。对于每个dequeue指令,若队列非空,则在单独的行中输出出队者的名字;对于每个deqteam指令,在单独的行中输出所有出队者的名字,以空格分隔。若队列为空,则不输出任何内容。
示例输入 2 3 101 102 103 3 201 202 203 enqueue 101 enqueue 201 enqueue 102 enqueue 202 deqteam 102 enqueue 203 dequeue dequeue dequeue dequeue dequeue dequeue stop 2 5 259001 259002 259003 259004 259005 6 260001 260002 260003 260004 260005 260006 enqueue 259001 enqueue 260001 enqueue 259002 enqueue 259003 enqueue 259004 enqueue 259005 dequeue dequeue enqueue 260002 enqueue 260003 deqteam 260002 dequeue dequeue dequeue stop 0 示例输出 Case #1: 101 102 201 202 203 Case #2: 259001 259002 260001 260002 260003 259003 259004 259005 代码实现
死锁 何为死锁?
在某些场景下,锁申请之后,没有及时释放,导致别人拿不到锁,然后程序锁死了
死锁的三种场景:
1.一个线程一把锁
public class demo2 { public static void main(String[] args) { synchronized (demo2.class) {//第一次上锁 synchronized (demo2.class) {//第二次上锁 ; } } } } 假如synchronized是不可重入锁
第二次上锁依赖第一次上锁释放,第一次上锁的释放需要执行完第二次上锁里的代码,就这样,二者互相等待,就导致锁死了。
2.两个线程互相获取对方锁
public class demo2 { public static void main(String[] args) { Object o1 = new Object(); Object o2 = new Object(); Thread t1 = new Thread() { public void run() { synchronized (o1) { try { sleep(1000);//等待t2线程上好他的o2锁 } catch (InterruptedException e) { e.
内部图表的大小是和外部设置的div容器息息相关的,如果想调整整个图表的空间占比,直接修改外部的div容器的宽高即可,但是如果是想设置图表与容器内部的上下以及左右的空白部分(div容器宽高不允许修改的情况下),即需要设置grid属性。
具体设置: grid: { x: 25, y: 45, x2: 5, y2: 25, borderWidth: 1, }, 部分代码展示: tooltip: { trigger: "axis", }, xAxis: { axisLabel: { color: "#A6B1C4", }, axisLine: { lineStyle: { color: "#264A88", }, }, axisTick: false, type: "category", data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], }, grid: { x: 25, y: 45, x2: 5, y2: 25, borderWidth: 1, }, yAxis: [ { name: "单位: 秒", nameTextStyle: { color: "
这里有前置要求:
需要已经编译通过过es源码!es源码能够自己本地成功运行。
https://blog.csdn.net/weixin_30166297/article/details/116751609
明确几个点 本篇文章,用类名 + . + function() 来表示某个类的某个方法。本篇文章的源码调试,用的是IDEA开发工具,快捷键是默认的!本篇文章说的点进去是指查看方法调用,是使用 ctrl + 鼠标左键点击 需要查看的方法,不再赘述。 列举重要的类(解析这些重要的类发挥的作用):
MetaStateService 用来做MetaData状态变更以后的落盘操作,包括从磁盘上将集群信息读回集群。Node类(这个类不好找org.elasticsearch.node)MetaData类 集群的信息 几个方向
如何定义API,需要理清楚es的调用关系。要知道如何从一个 DETELE index 然后调用到处理逻辑上去
理清楚处理类,es是如何删除一个索引的。
理清楚es的代码结构,这些类都在哪里放着。
需要知道es的IOC容器并不是用spring来管理的,要明白在es中是如何注册的。
如果是新加功能,如何写es中的测试类 ESIntegTestCase类是es的用于集成测试的类,它为我们封装了一些常用的方法,比如启动集群,创建索引,等等。
https://doc.codingdict.com/elasticsearch/504/https://www.twle.cn/l/yufei/elasticsearch/es-basic-testing.html 服务端 TransportDeleteIndexAction ,该类属于服务层的操作类。
TransportDeleteIndexAction 继承了 TransportMasterNodeAction,TransportMasterNodeAction是master节点来调度指定操作的类, 完成master节点执行和重试功能。
注意这里暂时省略了API层的分析,直接来到服务层看代码,核心代码在这里!
另外再说一点:这里并不是简单的API调用服务层。ES里边的处理逻辑是比较复杂。下边要讲的删除逻辑是真正执行删除的操作。但是API并没有直接调用它,删除流程是这样,通过es集群状态信息的变化,由这个变化的事件触发了调用删除逻辑。这样做的原因是:es是天然的分布式应用。状态信息的改变,首先发生在master节点上,然后master在将状态分发到数据节点上,在状态信息更新的时候,就捕捉到了这个变化的事件。然后就能够触发删除逻辑了。
执行删除操作的入口 TransportDeleteIndexAction.masterOperation()
源码如下:
TransportDeleteIndexAction.masterOperation()
@Override protected void masterOperation(final DeleteIndexRequest request, final ClusterState state, final ActionListener<AcknowledgedResponse> listener) { // 根据请求提取出来索引。 final Set<Index> concreteIndices = new HashSet<>(Arrays.asList(indexNameExpressionResolver.concreteIndices(state, request))); if (concreteIndices.isEmpty()) { listener.onResponse(new AcknowledgedResponse(true)); return; } // async delete freezing indices stats.
vue实现element-ui对话框可拖拽功能 element-ui对话框可拖拽及边界处理 项目中遇到了,记录一下。 // 新建dialogDrag.js // 自定义指令 v-dialogDrag import Vue from 'vue'; // v-dialogDrag: 弹窗拖拽属性 Vue.directive('dialogDrag', { bind(el, binding, vnode, oldVnode) { // el-dialog 组件 获取dom const dialogHeaderEl = el.querySelector('.el-dialog__header'); const dragDom = el.querySelector('.el-dialog'); // el-popover组件 获取dom // const dialogHeaderEl = el.querySelector('.el-popover__title'); // const dragDom = el.querySelector('.el-popover'); dialogHeaderEl.style.cssText += ';cursor:move;' dragDom.style.cssText += ';top:0px;' // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null); const sty = (function() { if (window.document.currentStyle) { return (dom, attr) => dom.
类别(category) category可以理解为给一个类“打补丁”的方法。它可以在不创建子类且不访问类原有源代码的前提下,给已有的类添加新的方法。
类别同样由接口和实现两部分组成,接口部分语法如下:
@interface 已有类 (类别名) //方法定义 ... @end 实现部分语法如下:
@implementation 已有类 (类别名) //方法实现 ... @end 如下程序,为NSNumber类添加加减乘除方法并进行了测试。
#import <Foundation/Foundation.h> //为NSNumber定义一个名为fk的类别 @interface NSNumber (fk) - (NSNumber*) add: (double) num2; - (NSNumber*) substract: (double) num2; - (NSNumber*) multiply: (double) num2; - (NSNumber*) divide: (double) num2; @end //为类别fk提供实现部分 @implementation NSNumber (fk) - (NSNumber*) add: (double) num2{ return [NSNumber numberWithDouble:([self doubleValue] + num2)]; } - (NSNumber*) substract: (double) num2{ return [NSNumber numberWithDouble:([self doubleValue] - num2)]; } - (NSNumber*) multiply: (double) num2{ return [NSNumber numberWithDouble:([self doubleValue] * num2)]; } - (NSNumber*) divide: (double) num2{ return [NSNumber numberWithDouble:([self doubleValue] / num2)]; } @end int main(int argc, char* argv[]){ @autoreleasepool{ NSNumber* myNum = [NSNumber numberWithInt:3]; NSNumber* add = [myNum add:2.
MySql 简单的查询操作 emp表如下:
dept表如下:
查询每个部门下的工作种类。(部门编号deptno + job组合在一起是不重复的。) select distinct deptno,job from emp1 员工转正后,月薪上调500元,请查询出所有员工转正后的月薪 select sal + 500 as 转正后月薪 from emp1 查询员工姓名,员工的工资,以及员工的年薪 select ename as 姓名,sal as 工资,sal * 12 as 年薪 from emp1 查询员工的年收入 select sal * 12 + ifnull(comm,0) as 年收入 from emp1 员工试用期6个月,转正后月薪上调20%,请查询出所有员工工作第一年的年薪所得(不考虑奖金部分,年薪的试用期6个月的月薪+转正后6个月的月薪) select sal*6+sal*1.2*6 from emp; 员工试用期6个月,转正后月薪上调20%,请查询出所有员工工作第一年的所有收入(需考虑奖金部分),要求显示列标题为员工姓名,工资收入,奖金收入,总收入 select ename 员工姓名, sal*6+sal*1.2*6 工资收入, ifnull(comm,0)*12奖金收入, sal*6+sal*1.2*6+ ifnull(comm,0)*12 总收入 from emp; 查询所有经理的编号 select mgr 经理编号 from emp1 where job = "
说明 ES中提供了一种强大的检索数据方式,这种检索方式称之为Query DSL ,Query DSL是利用Rest API传递JSON格式的请求体(Request Body)数据与ES进行交互,这种方式的丰富查询语法让ES检索变得更强大,更简洁。
语法 # GET /索引名/_doc/_search {json格式请求体数据} # GET /索引名/_search {json格式请求体数据} 测试数据 # 1.创建索引 映射 PUT /products/ { "mappings": { "properties": { "title":{ "type": "keyword" }, "price":{ "type": "double" }, "created_at":{ "type":"date" }, "description":{ "type":"text" } } } } # 2.测试数据 PUT /products/_doc/_bulk {"index":{}} {"title":"iphone12 pro","price":8999,"created_at":"2020-10-23","description":"iPhone 12 Pro采用超瓷晶面板和亚光质感玻璃背板,搭配不锈钢边框,有银色、石墨色、金色、海蓝色四种颜色。宽度:71.5毫米,高度:146.7毫米,厚度:7.4毫米,重量:187克"} {"index":{}} {"title":"iphone12","price":4999,"created_at":"2020-10-23","description":"iPhone 12 高度:146.7毫米;宽度:71.5毫米;厚度:7.4毫米;重量:162克(5.73盎司) [5] 。iPhone 12设计采用了离子玻璃,以及7000系列铝金属外壳。"} {"index":{}} {"title":"iphone13","price":6000,"created_at":"2021-09-15","description":"iPhone 13屏幕采用6.1英寸OLED屏幕;高度约146.7毫米,宽度约71.5毫米,厚度约7.65毫米,重量约173克。"} {"index":{}} {"title":"iphone13 pro","price":8999,"created_at":"2021-09-15","description":"iPhone 13Pro搭载A15 Bionic芯片,拥有四种配色,支持5G。有128G、256G、512G、1T可选,售价为999美元起。"} 常见检索 查询所有[match_all] match_all关键字: 返回索引中的全部文档
1. 什么是递归 函数自己调用自己本身,或者在自己函数调用的下级函数中调用自己 注意:使用递归函数要注意加上函数终止条件,避免进入死循环。
2. 案例 1. 求1,2,3,…n的和 function sum(n){ if( n == 1 ) return 1; return sum(n-1) + n; } 2. 求1,3,5,7,…第n项和前n项的和 先求出第n项的值 function getN(n){ if(n == 0) return 1; return getN(n-1) + 2; } 接着求前n项的和 function getN(n){ if(n == 0) return 1; return getN(n-1) + 2; } function sum(n){ if(n == 0) return 1; return getN(n) + sum(n-1); } 3. 斐波那契数列 1,1,2,3,5,8,13,21,34,55,89…求第 n 项 (后一项为前两项的和) function fib(n){ if(n == 0 || n ==1) return 1; return fib(n-1) + fib(n-2); } 4.
文章目录 搜索待删除节点正文(删除cur节点)情况1:cur.left = null① cur 为根节点② cur 为 parent 的左孩子③ cur 为 parent 的右孩子 情况2:cur.right = null① cur 为根节点② cur 为 parent 的左孩子③ cur 为 parent 的右孩子 情况3:cur.left != null && cur.right != null步骤①步骤② 删除 cur 节点代码 全代码 二叉搜索树的删除较为繁琐,但是静下心来相信很快就能吸收!主要分为两步:首先是查找待删除节点,然后针对这个节点进行删除。 我们用cur变量搜索,用parent变量表示curr的双亲结点
搜索待删除节点 搜索不是这篇文章的重点,我们直接上代码
public boolean delete(int key) { // wirte code here,主要分为三种情况 Node parent = null; Node cur = root;//cur负责找到需要删除的节点 while (cur != null) { if (cur.key < key) { parent = cur; cur = cur.
文章目录 前言一、创建原理图库1.1新建工程1.2.设置原理图板框1.3.设置原理图栅格 二、添加多个原理图2.1、原理图重命名2.2、原理图编页码 三、放置元器件3.1、添加库3.2、连线 四、保存工程文件4.1、新建原理图库 总结 前言 相信很多学生也和我一样,在一个类似于叫EDA的课上通过DXP/Altium Designer学习绘制PCB电路,因此大多数学生应该是会用AD这款软件的,至少最基本的流程不会出问题。但是目前企业的环境中,AD的使用频率却远没有那么高。很大一部分程度上是由于正版的AD很贵,而且他的公司满世界的寄律师函,打击盗版行为;另一个原因是AD的版本更新太快了,一年一个大版本都是小意思,这就导致工程师需要相当时间精力去用在适应新软件上,属实麻烦。
cadence allergo是一系列软件的代称,它包含了从绘制电路图到绘制版图/PCB图的一切流程功能。现在先从绘制原理图库起步,学习allergo。
至于AD还是Candence 好,各有千秋,说法不一,我们抱着理性的态度去看就行了,
大家可以看看网友怎么说的 :Cadence真的比Altium强吗?为什么要鄙视AD呢?
软件版本:Candence 17.2 虽然有7.2个G,但是启动速度真的比AD快很多,很流畅。
一、创建原理图库 首先原理图绘制与原理图库设计的软件是这个,第二个是来绘制PCB的
首先安装咱就不说了,大家可以去b站搜索就行,第一次我们可能会碰到下图,我们选择OrCAD Capture CIS 然后勾选默认开启就行了。
然后我们可以看到这样的界面,点击我们的new project
1.1新建工程 选择好工程的存放位置,最好事先新建一个专门的工程文件夹
然后就可以看到我们默认有一个PAGE
然后点击可以看到我们的原理图
1.2.设置原理图板框 点击选项 options 点击sch…,这个版本它默认给我勾选好了
1.3.设置原理图栅格 点击选项 options 点击preference 中的Grid Display,我们可以选择点或者线,这里我们选择线。
二、添加多个原理图 Candence 的好处就是我所有的原理图可以分开保存,但是在外面保存是按照一个整体来保存的也就是DSN文件。并且元件库非常丰富,不用我们自己画就像mutism一样。
这里我们分为10个子原理图,分模块设计
右键改名rename,01 空格 OverView符合我们的设计习惯,这样就可以按顺序来设计了,记得按ctrl +s保存
2.1、原理图重命名 原理图右键NEW page,记得按ctrl +s保存
以此类推,依次完成重命名
2.2、原理图编页码 我们一共有10页,所以要给每一页编页码
按照我们刚才的序号来,代表10页里面的第几页
编完页码后就可以放置我们的元器件了
三、放置元器件 我们点击右侧的place part
我们发现啥都没有,那肯定要添加的,我们点击add library ,发现自带的已经有很多库了,
库的介绍可以参考这个博主的介绍,非常详细,几乎常用的都有了。
https://blog.csdn.net/LGCPCB/article/details/88364199?utm_source=app&app_version=4.13.0&utm_source=app
3.1、添加库 我们打开常用的Discrete,常用的电阻电容都在这里
点击我们这个,就可以放置了,放置好了就可以连线了,ESC是退出我们的元件放置
或者按快捷键W 英文模式下的快捷键,然后就可以像mutism一样连线了,这个连线是电气连线的意思。
文章目录 Eigen简介下载解压建立VSCode工作区新建main.cpp文档及源码 Eigen 简介 Eigen是一个用来进行矩阵处理的C++库,除了 C++ 标准库之外,Eigen 不需要其他任何依赖项。
下载 官网 https://eigen.tuxfamily.org
直接点击最新版(当前是3.4.0)对应的zip文件下载即可。
解压 解压后文件目录如下:
. └─eigen-3.4.0 ├─.gitlab │ ├─issue_templates │ └─merge_request_templates ├─bench │ ├─btl │ │ ├─actions │ │ ├─cmake │ │ ├─data │ │ ├─generic_bench │ │ │ ├─init │ │ │ ├─static │ │ │ ├─timers │ │ │ └─utils │ │ └─libs │ │ ├─BLAS │ │ ├─blaze │ │ ├─blitz │ │ ├─eigen2 │ │ ├─eigen3 │ │ ├─gmm │ │ ├─mtl4 │ │ ├─STL │ │ ├─tensors │ │ ├─tvmet │ │ └─ublas │ ├─perf_monitoring │ │ └─resources │ ├─spbench │ └─tensors ├─blas │ ├─f2c │ ├─fortran │ └─testing ├─ci ├─cmake ├─debug │ ├─gdb │ └─msvc ├─demos │ ├─mandelbrot │ ├─mix_eigen_and_c │ └─opengl ├─doc │ ├─examples │ ├─snippets │ └─special_examples ├─Eigen │ └─src │ ├─Cholesky │ ├─CholmodSupport │ ├─Core │ │ ├─arch │ │ │ ├─AltiVec │ │ │ ├─AVX │ │ │ ├─AVX512 │ │ │ ├─CUDA │ │ │ ├─Default │ │ │ ├─GPU │ │ │ ├─HIP │ │ │ │ └─hcc │ │ │ ├─MSA │ │ │ ├─NEON │ │ │ ├─SSE │ │ │ ├─SVE │ │ │ ├─SYCL │ │ │ └─ZVector │ │ ├─functors │ │ ├─products │ │ └─util │ ├─Eigenvalues │ ├─Geometry │ │ └─arch │ ├─Householder │ ├─IterativeLinearSolvers │ ├─Jacobi │ ├─KLUSupport │ ├─LU │ │ └─arch │ ├─MetisSupport │ ├─misc │ ├─OrderingMethods │ ├─PardisoSupport │ ├─PaStiXSupport │ ├─plugins │ ├─QR │ ├─SparseCholesky │ ├─SparseCore │ ├─SparseLU │ ├─SparseQR │ ├─SPQRSupport │ ├─StlSupport │ ├─SuperLUSupport │ ├─SVD │ └─UmfPackSupport ├─failtest ├─lapack ├─scripts ├─test └─unsupported ├─bench ├─doc │ ├─examples │ │ └─SYCL │ └─snippets ├─Eigen │ ├─CXX11 │ │ └─src │ │ ├─Tensor │ │ ├─TensorSymmetry │ │ │ └─util │ │ ├─ThreadPool │ │ └─util │ └─src │ ├─AutoDiff │ ├─BVH │ ├─Eigenvalues │ ├─EulerAngles │ ├─FFT │ ├─IterativeSolvers │ ├─KroneckerProduct │ ├─LevenbergMarquardt │ ├─MatrixFunctions │ ├─MoreVectorization │ ├─NonLinearOptimization │ ├─NumericalDiff │ ├─Polynomials │ ├─Skyline │ ├─SparseExtra │ ├─SpecialFunctions │ │ └─arch │ │ ├─AVX │ │ ├─AVX512 │ │ ├─GPU │ │ └─NEON │ └─Splines └─test 其中Eigen就是存放要Include的头文件的地方。
进程状态 进程主要有7种状态:就绪状态、运行状态、轻度睡眠、中度睡眠、深度睡眠、僵尸状态、死亡状态。它们之间状态变迁如下:
进程描述符task_struct结构体中有个成员state专门用来描述进程的状态。
就绪状态:state为TASK_RUNNING,正在运行队列中等待调度器调度。运行状态:state为TASK_RUNNING,被调度器命中,正在处理器中运行。轻度睡眠:称为可打断的睡眠状态。state为TASK_INTERRUPTIBLE,可以被信号打断。中度睡眠:state为TASK_KILLABLE,只能被致命的信号打断。深度睡眠:不可打断的睡眠状态。state为TASK_UNINTERRUPTIBLE,不能被信号打断。死亡状态:state为TASK_DEAD。在task_struct中还另外有一个字段exit_state为EXIT_DEAD。僵尸状态:state为TASK_DEAD。在task_struct中还另外有一个字段exit_state为EXIT_ZOMBIE。如果父进程关注子进程退出事件,那么子进程在退出时
发送SIGCHILD信号通知父进程,变成僵尸进程。父进程在查询子进程终止原因后收回子进程的进程描述符。 调度算法原则 良好的调度算法应该考虑以下几个问题:
公平:保证每个进程得到合理的cpu时间。高效:使cpu保持忙碌状态,即总是有进程在cpu上执行响应时间:使交互用户的响应时间尽可能短周转时间:使批处理用户等待输出的时间尽可能短吞吐量:使单位时间内处理的进程数量尽可能多 举几个遵循以上原则的例子,比如unix系统采用的动态优先调度,windows的抢先多任务调度。
进程调度的依据 在include/sched.h的task_struct结构体中,有以下几个成员,注意这些成员的代码不是在一起的,这里只是把它们贴在一起了。
//在调度时机到来时检测该值,如果为1则调用schedule() volatile long need_resched; //进程处于运行状态时所剩的时钟嘀嗒数。每次时钟中断到来时,这个值减1,直到减为0 //如果该值为0,就把need_resched置为1。这个值也称为动态优先级 long counter; //进程的静态优先级。这个值决定了counter的初值 long nice; //实时进程的优先级 unsigned long rt_priority; //从整体上区分实时进程和普通进程,因为实时进程和普通进程的调度不同,实时进程应当优于普通进程执行。可以通过系统调用sched_setscheduler()来改变调度的策略 unsigned long policy; 进程调度策略 进程优先级 限期进程的优先级比实时进程高,实时进程的优先级比普通进程高。
限制进程的优先级是-1。
实时进程的实时优先级是1-99,优先级数值越大,表示优先级越高。
普通进程的静态优先级是100-139,优先级值越小,表示优先级越高,可通过修改nice值改变普通进程的优先级,优先级等于120加上nice值。
在task_struct结构体中,4个成员和优先级有关如下:
int prio; int static_prio; int normal_prio; unsigned int rt_priority; 具体来说这4个成员的关系如下:
有一点值得注意,如果优先级低的进程占有实时互斥锁,此时又有优先级高的进程等待实时互斥锁,这时会把占有实时互斥锁的进程的优先级临时提高到等待实时互斥锁的进程的优先级,这个现象叫优先级继承。
限期调度策略 有三个参数:运行时间runtime、截止期限deadline和周期period。每个周期运行一次,一次运行的时长为runtime。
具体的调度策略:选取一个绝对截止期限最小的进程,执行了runtime时长后,如果还未完成就让出cpu,并在运行队列中删除,下一个周期开始时再加入。
实时进程调度策略 支持两种调度策略。
先进先出调度策略:没有时间片,如果没有更高优先级的实时进程,并且该实时进程不睡眠,那么它将一直占有处理器。轮流调度策略:有时间片,进程用完时间片以后会加入优先级对应运行队列的队尾,把处理器给优先级相同的其他进程。 普通进程调度策略 标准轮流分时调度策略:使用完全公平调度算法,把处理器时间公平分给每个进程。空闲调度策略:该策略用来执行优先级非常低的进程,优先级比使用标准轮流分时调度策略中相对优先级(nice)为19的普通进程还低。进程的相对优先级对空闲调度策略没有影响。 调度类 注意是调度器里面包含进程,而不是进程里包含调度器,特别是不要因为看见task_struct中有个sched_class*成员,就记错了。不同的进程对应不同的调度器,但是一个进程只能属于一个调度器。
停机调度类 停机调度类是优先级最高的调度类,支持限期调度类。停机进程优先级最高,可抢占其他所有进程。没有时间片,如果不主动让出cpu就会一直占有。目前只有停机线程属于停机调度类。设计停机调度类的目的,是为了让迁移线程的优先级比限期进程高,才能快速处理调度器发出的迁移指令,把进程从当前处理器迁移到其他处理器。停机进程对外伪装成最高优先级的实时进程。
限期调度类 使用优先算法(使用红黑树)把进程按绝对截止期限从小到大排序,每次调度时选择绝对截止期限最小的进程。
实时调度类 为每个优先级维护一个源码。
/* * This is the priority-queue data structure of the RT scheduling class: */ struct rt_prio_array { DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* include 1 bit for delimiter */ struct list_head queue[MAX_RT_PRIO]; }; 位图bitmap用来快速查找第一个非空队列,数组queue的下标是实时进程调度优先级,下标越小,优先级越高。
例如,给定矩阵a = [[1,2,3], [4,5,6], [7,8,9]]
将矩阵a中不为0的元素挑选出来组合成为一维向量:
c = [1, 2, 3, 4, 5, 6, 7, 8, 9]
一般思路就是两层for循环挨个添加,有更加简洁的方式:
a = torch.from_numpy(np.array([[1,2,3], [4,5,6], [7,8,9]])) b = a.nonzero() c= a[b[:,0], b[:,1]] np.array(list):将list转换为numpy矩阵
torch.from_numpy(nparray):将numpy矩阵转换为tensor数组
tensor.nonzero():返回tensor矩阵中不为0元素的索引,对于2维矩阵来说,索引就是n*2的维度;
一些结果:
a = torch.from_numpy(np.array([[1,2,3], [4,5,6], [7,8,9]])) print(a) tensor([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=torch.int32) a = torch.from_numpy(np.array([[1,2,3], [4,5,6], [7,8,9]])) b = a.nonzero() print(b) tensor([[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], [2, 0], [2, 1], [2, 2]]) a = torch.
平时大概率我们会构建一些树形结果返回给前端,比如菜单结构、部门列表、文件结构等,我们一般想到的就是利用递归来循环构建;现在,就我个人解决的方法如下:
原始递归利用Java 8 Stream流进行处理(原理还是递归)Stream流升级构建 场景构建 public class TreeSelect implements Serializable { /** 节点ID */ private Long id; /** 节点名称 */ private String label; /** 父ID */ private Long parentId; /** 子节点 */ private List<TreeSelect> children; public TreeSelect() { } public TreeSelect(Long id, String label, Long parentId) { this.id = id; this.label = label; this.parentId = parentId; } public TreeSelect(TreeSelect treeSelect) { this.id = treeSelect.getId(); this.label = treeSelect.getLabel(); this.children = treeSelect.
一、 问题描述 绘制以z=f(y)为母线绕z或y轴的旋转曲面,要求:
用户自行决定曲面网格的疏密;
用户输入旋转轴;
用图像给生成的曲面贴上纹理,图像预载入或用户输入
二、 求解思路 利用cylinder函数,输入母线和范围,即可使用surf函数画出旋转图
绕y轴时,直接使用原函数,利用linspace函数将区间分割为等间距的点后,带入母线函数中。
绕z轴时,使用原函数的反函数,先将用户输入的字符串解读,定义符号变量,产生符号函数,再利用finverse输出反函数的内含函数,后面的操作如图。
本程序可以解决单调或者半侧单调的函数绕y轴或者绕z轴或者不单调函数绕y轴的情况,对于不单调的函数绕z轴的情况,由于无法求得正确的反函数,在画绕z轴时将失效
此外,本程序在输入时也考虑了用户输入含变量x的情况,对于可以操作的情况,本程序以允以支持,对于无法操作的情况(输入函数的自变量,变量和绕的轴都不相同),本程序将允以拒绝
三、 程序代码 clear; clc; close all qidian=pi/2; zhongdian=2*pi+pi/4; jiange=10; s=input("输入函数表达式:如('z=y.^2')"); [xall,p]=strsplit(s,'='); x1=cell2mat(xall(1)); x2=cell2mat(xall(2)); pat=['x','y','z']; for i=1:3 k1=contains(x1,pat(i)); if k1==1 judge1=pat(i); end k2=contains(x2,pat(i)); if k2==1 judge2=pat(i); end end qidian=input("请输入(自变量)起点:"); zhongdian=input("请输入(自变量)终点:"); jiange=input("请输入间隔:"); zhou=input("请输入中心轴( 'y' or 'z')"); tupian=input("请输入要贴入的图片('图片名')"); if ~isequal(judge1,judge2,zhou) f=inline(x2); if ~(judge2==zhou) lin=linspace(qidian,zhongdian,1000); zhongdian=max(f(lin)); qidian=min(f(lin)); syms x tempf(x)=f(x); f=inline(finverse(tempf)); end [X,Y,Z]=fun(f,qidian,zhongdian,jiange,zhou,tupian); else disp('无法画图') end function [X,Y,Z]=fun(f,qidian,zhongdian,jiange,zhou,tupian) lin=linspace(qidian,zhongdian,jiange); x=f(lin); if zhou=='z' [X,Y,Z]=cylinder(x); else [X,Z,Y]=cylinder(x); end h=surf(X,Y,Z); axis square [mx,mp]=imread(tupian); set(h,'CData',flipdim(mx,1),'FaceColor','texturemap','EdgeColor','none') end 四、 实验结果 五、 实验心得 Matlab本身自带许多功能强大的函数,合理运用这些函数时,将取得事半功倍的效果,然而一旦盲目使用这些函数,将会使得实验走向死胡同或者一些无法解决的结果
测试不止是点点点 我感觉我是一个比较有发言权的人吧,我在测试行业摸爬滚打5年,以前经常听到开发对我说,天天的点点点有意思没?
和IT圈外的同学、朋友聊起自己的工作,往往一说自己是测试,无形中也会被大家轻视,总有人会问你,为啥干测试啊,怎么不干开发呢?不可否认,在他们心中,你肯定是因为能力不足,无法胜任开发的工作,所以只能干着平凡、索然无味的测试工作。但是我的经验告诉你,测试并不只是单纯的点点点…只要你肯努力
我刚出来的时候是在外包做功能测试,天天点点点,很悠闲,点了两年,随着时间的消磨,让我产生了对自我价值和岗位意义的困惑。薪资也得不到提升,看着身边的人不断涨薪,或者跳槽去了更好的公司,特别觉得自己跌落谷底,碌碌无为…
开始入门自动化测试 不得已开始思考怎么去改变现状,公司最开始只我一位软件测试人员,没有任何流程和规范,但好在工作比较轻松,这就导致我有充足的时间学习各种测试技术和工具。当时,有一些机会在工作中做性能测试,于是,学会了使用LoadRunner和JMeter,有一次需要测试MySQL数据库的性能,用JMeter搞了半天不知道怎么设置,结果叫一位开发的同事帮我过来很快就搞定了。
让我明白了开发知识对于测试工作的帮助,编程语言的能力会决定你测试技术的深度。当然也能带来收入的高度。
那时候正是脚本语言开始流行起来,偶然在一个技术群中,听说基于Python的自动化测试,特别好上手,我便开始了新的尝试。
在入门阶段,要有很强的自制力,平常比较好学,平常没什么事情的时候都会自己在网上找资源报班学习,学敲代码,每天下班回来就抽出一个小时看视频做笔记,慢慢地也懂了一些测试开发方面的知识。
怀着这份野心,先是花小半年时间学习了UI自动化,需要学的内容有很多。学习过程中所有的知识都是零散的,想要组合起来对一个小白来说确实不容易。有了UI自动化学习经验,学习接口自动化基本没有费什么功夫。
UI自动化,接口自动化学完了,因为工作需要又去学了性能,后来发现性能真的是个无底洞,需要了解开发知识、服务器架构、操作系统、测试监控工具、容器知识等等。知识面太广,现在还在苦苦挣扎。在性能测试过程中,也去学了一些开发知识,之前做UI/接口自动化或者功能测试时只能从黑盒/灰盒层面去判断BUG原因,学了开发知识后,大概就知道这个bug是如何产生了。
测试开发 当时由于公司的规模和产品的局限性,导致自动化测试始终未能应用到公司实战项目中。我觉得外面的大公司有更多机会,现在自动化已经流行而且越来越普及,我想要突破自己的测试技术瓶颈,专职做自动化,偶然机会下朋友推荐我去一家金融公司做测试开发,负责开发公司定制化的测试质量平台。
这对于我来说又是一个挑战,新的领域,测试开发在一线城市非常吃香。当时的待遇比初、中级开发工程师要高。
到岗后就是顶住压力,不断的学习测试开发技能,而且学以致用。技术架构采用的是前后端分享,包括Python的后端开发框架Flask,前端框架vue,elementUI组件等,这对我自己的测试生涯也算是有了一个提高。薪资方面也有了一个大的突破!(突然发现,自己还是涉足挺广)。算是证明了自己…
没有努力过就不要说测试这个行业没前途,作为一个过来人,对学习过程中的困难深有体会。
如果你也在往自动化测试开发方向发展,在适当的年龄,选择适当的岗位,将自己的优势都发挥出来!
我的自动化测试之路,一路走来都离不每个阶段的计划,因为自己喜欢规划和收集总结,所以,我和朋友特意花了一段时间整理编写了下面的《自动化测试工程师学习路线》,也整理了不少【网盘资源】,需要的朋友可以点击下方小卡片获取网盘链接。希望会给你带来帮助和方向。
【自动化测试学习路线】 1. 自动化测试必备Python编程内容 2. Web UI 自动化测试基础内容 3. Web UI 自动化测试实战内容 4. APP UI 自动化测试基础内容 5. APP UI 自动化测试实战内容 6. API 接口自动化测试基础内容 7. API 接口自动化测试实战内容 8. CI/CD持续集成专项技术 9. 自动化测试框架实战技术 上面就是我整理出来的一份自动化测试工程师技术路径图。希望大家能在这个成长过程中收益良多。全方位提升测试技术,建立一套属于自己的技术体系。帮助大家不断学习和优化技术栈,跟进先进和主流的测试技术,给到大家带来的不仅仅是技术和薪资的提升,更多的是改变测试人在IT技术领域的地位和心态,拔高测试行业的技术深度。
最后感谢每一个认真阅读我文章的人,下面这个自动化网盘链接也是我费了几天时间整理的非常全面的,希望也能帮助到有需要的你!
这些资料,对于做【软件测试】想进阶的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你!凡事要趁早,特别是技术行业,一定要提升技术功底。希望对大家有所帮助…….
1,园区网络基本概念
什么是园区网
• 园区网络的规模可大可小,小到一个SOHO(Small Office Home Office,家居办公室),
大到校园、企业园区、公园、购物中心等。园区的规模是有限的,一般的大型园区,例如
高校园区、工业园区,规模依然被限制在几平方公里以内,在这个范围内,我们可以使用
局域网技术构建网络。超过这个范围的“园区”通常被视作一个“城域”,需要使用到广
域网技术,相应的网络会被视作城域网。
• 园区网络使用的典型局域网技术包括遵循IEEE(Institute of Electrical and Electronics Engineers,电气和电子工程师协会) 802.3 标准的Ethernet 技术(有线)和遵循IEEE 802.11 标准的Wi-Fi 技术(无线)。
园区网络典型架构
• 园区网络典型层次和区域:
▫ 核心层:是园区网骨干,是园区数据交换的核心,联接园区网的各个组成部分,如数
据中心、管理中心、园区出口等。
▫ 汇聚层:处于园区网的中间层次,完成数据汇聚或交换的功能,可以提供一些关键的
网络基本功能,如路由、 QoS、安全等。
▫ 接入层:为终端用户提供园区网接入服务,是园区网的边界。
▫ 出口区:园区内部网络到外部网络的边界,用于实现内部用户接入到公网,外部用户
接入到内部网络。一般会在此区域中部署大量的网络安全设备来抵御外部网络的攻击,
如IPS(intrusion prevention system,入侵防御系统)、Anti-DDoS设备、Firewall
(防火墙)等。
▫ 数据中心区:部署服务器和应用系统的区域,为企业内部和外部用户提供数据和应用
服务。
▫ 网络管理区:部署网络管理系统的区域,包括SDN控制器,无线控制器,eLOG(日
志服务器)等,管理监控整个园区网络。
小型园区网络典型架构
中型园区网络典型架构
大型园区网络典型架构
园区网络主要协议/技术
2,园区网络项目实战
园区网络项目生命周期
• 网络的规划与设计是一个项目的起点,完善细致的规划工作将为后续的项目具体工作打下
坚实的基础。
• 项目实施是工程师交付项目的具体操作环节,系统的管理和高效的流程是确保项目实施顺
利完成的基本要素。
• 要保证网络各项功能正常运行、从而支撑用户业务的顺利开展,需要对网络进行日常的维
护工作和故障处理。
• 用户的业务在不断发展,因此用户对网络功能的需求也会不断变化。当现有网络不能满足
业务需求,或网络在运行过程中暴露出了某些隐患时,就需要通过网络优化来解决。
小型园区网络设计
组网方案设计
目录
环境说明:
1.添加用户
2.安装配置
3.配置日志收集(详情见)
4.修改启动脚本,配置开机启动
5.启动方式说明
5.1指定配置文件启动方式
5.2 启动方式二
6.健康监测
7.haproxy实现持久连接
8.管理界面信息查看
配置参数说明(以下为转载内容)
1.全局配置参数
1.1.进程管理及安全相关的参数。
1.2.性能调整相关的参数。
2. proxy配置段和常用配置选项
http事务模型相关设置
balance
hash-type
bind
mode
log
capture request header和capture response header
maxconn
use_backend
default_backend
server和default-server
option httpchk
stats相关
option forwardfor
错误页面相关
cookie和option redispatch
reqadd和rspadd
超时时间相关
http协议过滤:http-request
tcp请求和响应过滤
3. ACL
3.1 ACL语法
3.2 ACL实现动静分离示例
环境说明: 组件主机备注Haproxy192.168.32.200下载地址sharding-proxy192.168.1.166:3307sharding-proxy192.168.1.166:3308sharding所在宿主机192.168.1.166 cd /home mkdir haproxy cd /home/haproxy 1.添加用户 #添加haproxy组
groupadd -r haproxy
#创建nginx运行账户haproxy并加入到haproxy组,不允许haproxy用户直接登录系统
useradd -r -g haproxy -M -s /sbin/nologin haproxy 上次下载好的安装包到home/haproxy目录下
一.第一步:导入两个jar包。
activation.jar 和 mail.jar, 一定要添加到构建路径(不然找不到包)
两个用于Java发送邮件的jar包-Java文档类资源-CSDN下载
二、创建邮箱工具类:Mail.java
import java.util.*; import java.io.*; import javax.mail.*; import javax.mail.internet.*; import javax.activation.*; public class Mail { String to = "";// 收件邮箱 String from = "";// 发件邮箱 String host = "";// smtp主机 服务器地址 String username = ""; //登录服务器校验用户 String password = ""; //登录服务器校验密码 String filename = "";// 附件文件名 String subject = "";// 邮件主题 String content = "";// 邮件正文 Vector file = new Vector();// 附件文件集合 public Mail() { } //构造器,提供直接的参数传入 public Mail(String to, String from, String smtpServer, String username, String password, String subject, String content) { this.
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录 检查点回放注意 检查点 loadrunner中检查点是用来判断脚本是否执行成功的。
不加检查点,只要服务器返回的HTTP状态码是200,Vugen就认为脚本执行通过了,但是很多情况下服务器返回200并不代表脚本执行通过了。
比如:登录操作,登录失败服务器返回的也是200,但是实际上它是执行失败了。所以在脚本调试时,我们一般会加上检查点来判断脚本是否执行通过。
我们是在脚本调试过程中需要加上检查点,在实际的压测过程中是否需要加检查点呢?尽量不要使用,除非迫不得已,因为脚本里面加入了检查点就多了一步操作,对测试结果会有一定的影响。假如请求是会往数据库里面插入数据的,我们就可以不使用检查点,可以通过测试结果中的通过事物总数和数据库中插入的数据条数进行对比,如果一致则说明所有请求都是成功的。如果不会往数据库中插入数据,比如查询操作,则最好是加入检查点。
检查点也可以用于检查在服务器压力较大时,是否能够准确的返回指定的测试对象。
web_reg_find("Search=All", "SaveCount=registerflag", "Text=X-Frame-Options: SAMEORIGIN", LAST); //放在最后 if(atoi(lr_eval_string("{registerflag}"))>0) { lr_output_message("wangmin pass"); return 0; } else { lr_output_message("wangmin failed"); return -1; } 回放 注意 在回放脚本时,必须确定run-time setting中勾选了“Enable Image and text check”选项。如果不勾选此项,脚本回放将不会执行检查点函数