1 #include<stdio.h> 2 3 typedef struct node{ 4 int data;//数据域 5 struct node * pNext;//指针域,指向跟本身一样的数据类型(struct node) 6 }NODE,*PNODE;//NODE==struct node, 7 PNODE==struct node * 8 9 int main(){ 10 return 0; 11 } 链表的分类: 单链表 双链表: 每一个节点有两个指针域,左边指针域指向前面的,右边指针域指向后面的
循环链表: 能通过任何一个节点找到其他所有的节点,最后一个节点的指针域指向第一个节点
非循环链表 转载于:https://www.cnblogs.com/sunbr/p/11318605.html
一:自身可枚举属性
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 。如果对象的键-值都不可枚举,那么将返回由键组成的数组。
这是合理的,因为大多数时候只需要关注对象自身的属性。
来看看一个对象拥有自身和继承属性的例子,Object.keys()只返回自己的属性键:
let simpleColors = { nameA: 'a', nameB: 'b' }; let natureColors = { colorC: 'green', colorD: 'yellow' }; Object.setPrototypeOf(natureColors, simpleColors); Object.keys(natureColors); // => ['colorC', 'colorD'] natureColors['nameA']; // => 'a' natureColors['nameB']; // => 'b' Object.setPrototypeOf() 方法设置一个指定的对象的原型 ( 即, 内部[[Prototype]]属性)到另一个对象或 null。
Object.keys(natureColors)返回natureColors对象的自身可枚举属性键:['colorC','colorD']。
natureColors包含从simpleColors原型对象继承的属性,但是Object.keys()函数会跳过它们。
Object.values() 和 Object.entries() 也都是返回一个给定对象自身可枚举属性的键值对数组
Object.values(natureColors); // => ['green', 'yellow'] Object.entries(natureColors); // => [ ['colorC', 'green'], ['colorD', 'yellow'] ] 现在注意与for..in语句的区别,for..in不仅可以循环枚举自身属性还可以枚举原型链中的属性
let enumerableKeys = []; for (let key in natureColors) { enumerableKeys.
::-webkit-scrollbar-track-piece { -webkit-border-radius: 0 } ::-webkit-scrollbar { width: 5px; height: 10px } ::-webkit-scrollbar-thumb { height: 50px; background-color: #b8b8b8; -webkit-border-radius: 6px; outline-offset: -2px; filter: alpha(opacity = 50); -moz-opacity: 0.5; -khtml-opacity: 0.5; opacity: 0.5 } ::-webkit-scrollbar-thumb:hover { height: 50px; background-color: #878987; -webkit-border-radius: 6px }
文章目录 摘要1.介绍2.编程模型2.1 实例2.2类型2.3更多实例 3.实现3.1执行预览3.2master数据结构3.3容错3.4存储位置3.5任务粒度3.6备用任务 4.技巧4.1分割函数4.2顺序保证4.3combiner函数4.4输入输出类型4.5副作用4.6跳过错误记录4.7本地执行4.8状态信息4.9计数器 5.性能5.1机群配置5.2Grep5.3排序5.4备用任务的影响5.5机器失效 6.经验6.1大规模索引 7.相关工作8.结束语 摘要 MapReduce是一个编程模型,和处理,产生大数据集的相关实现.用户指定一个map函数处理一个key/value对,从而产生中间的key/value对集.然后再指定一个reduce函数合并所有的具有相同中间key的中间value.下面将列举许多可以用这个模型来表示的现实世界的工作.
以这种方式写的程序能自动的在大规模的普通机器上实现并行化.这个运行时系统关心这些细节:分割输入数据,在机群上的调度,机器的错误处理,管理机器之间必要的通信.这样就可以让那些没有并行分布式处理系统经验的程序员利用大量分布式系统的资源.
我们的MapReduce实现运行在规模可以灵活调整的由普通机器组成的机群上,一个典型的MapReduce计算处理几千台机器上的以TB计算的数据.程序员发现这个系统非常好用:已经实现了数以百计的MapReduce程序,每天在Google的机群上都有1000多个MapReduce程序在执行.
1.介绍 在过去的5年里,作者和Google的许多人已经实现了数以百计的为专门目的而写的计算来处理大量的原始数据,比如,爬行的文档,Web请求日志,等等.为了计算各种类型的派生数据,比如,倒排索引,Web文档的图结构的各种表示,每个主机上爬行的页面数量的概要,每天被请求数量最多的集合,等等.很多这样的计算在概念上很容易理解.然而,输入的数据量很大,并且只有计算被分布在成百上千的机器上才能在可以接受的时间内完成.怎样并行计算,分发数据,处理错误,所有这些问题综合在一起,使得原本很简介的计算,因为要大量的复杂代码来处理这些问题,而变得让人难以处理.
作为对这个复杂性的回应,我们设计一个新的抽象模型,它让我们表示我们将要执行的简单计算,而隐藏并行化,容错,数据分布,负载均衡的那些杂乱的细节,在一个库里.我们的抽象模型的灵感来自Lisp和许多其他函数语言的map和reduce的原始表示.我们认识到我们的许多计算都包含这样的操作:在我们输入数据的逻辑记录上应用map操作,来计算出一个中间key/value对集,在所有具有相同key的value上应用reduce操作,来适当的合并派生的数据.功能模型的使用,再结合用户指定的map和reduce操作,让我们可以非常容易的实现大规模并行化计算,和使用再次执行作为初级机制来实现容错.
这个工作的主要贡献是通过简单有力的接口来实现自动的并行化和大规模分布式计算,结合这个接口的实现来在大量普通的PC机上实现高性能计算.
第二部分描述基本的编程模型,并且给一些例子.第三部分描述符合我们的基于集群的计算环境的MapReduce的接口的实现.第四部分描述我们觉得编程模型中一些有用的技巧.第五部分对于各种不同的任务,测量我们实现的性能.第六部分探究在Google内部使用MapReduce作为基础来重写我们的索引系统产品.第七部分讨论相关的,和未来的工作.
2.编程模型 计算利用一个输入key/value对集,来产生一个输出key/value对集.MapReduce库的用户用两个函数表达这个计算:map和reduce.
用户自定义的map函数,接受一个输入对,然后产生一个中间key/value对集.MapReduce库把所有具有相同中间key I的中间value聚合在一起,然后把它们传递给reduce函数.
用户自定义的reduce函数,接受一个中间key I和相关的一个value集.它合并这些value,形成一个比较小的value集.一般的,每次reduce调用只产生0或1个输出value.通过一个迭代器把中间value提供给用户自定义的reduce函数.这样可以使我们根据内存来控制value列表的大小.
2.1 实例 考虑这个问题:计算在一个大的文档集合中每个词出现的次数.用户将写和下面类似的伪代码:
map(String key,String value): //key:文档的名字 //value:文档的内容 for each word w in value: EmitIntermediate(w,"1"); reduce(String key,Iterator values): //key:一个词 //values:一个计数列表 int result=0; for each v in values: result+=ParseInt(v); Emit(AsString(resut)); map函数产生每个词和这个词的出现次数(在这个简单的例子里就是1).
reduce函数把产生的每一个特定的词的计数加在一起.
另外,用户用输入输出文件的名字和可选的调节参数来填充一个mapreduce规范对象.用户然后调用MapReduce函数,并把规范对象传递给它.用户的代码和MapReduce库链接在一起(用C++实现).附录A包含这个实例的全部文本.
2.2类型 即使前面的伪代码写成了字符串输入和输出的term格式,但是概念上用户写的map和reduce函数有关联的类型:
map(k1,v1) ->list(k2,v2)
reduce(k2,list(v2)) ->list(v2)
例如,输入的key,value和输出的key,value的域不同.此外,中间key,value和输出key,values的域相同.
我们的C++实现传递字符串来和用户自定义的函数交互,并把它留给用户的代码,来在字符串和适当的类型间进行转换.
2.3更多实例 这里有一些让人感兴趣的简单程序,可以容易的用MapReduce计算来表示.
分布式的Grep(UNIX工具程序, 可做文件内的字符串查找):如果输入行匹配给定的样式,map函数就输出这一行.reduce函数就是把中间数据复制到输出.
计算URL访问频率:map函数处理web页面请求的记录,输出(URL,1).reduce函数把相同URL的value都加起来,产生一个(URL,记录总数)的对.
倒转网络链接图:map函数为每个链接输出(目标,源)对,一个URL叫做目标,包含这个URL的页面叫做源.reduce函数根据给定的相关目标URLs连接所有的源URLs形成一个列表,产生(目标,源列表)对.
switch与if-else的区别 switch与if else的执行效率这里简单的总结一下: switch与if else的执行效率 单从JVM的执行效率上讲的话,switch的执行效率要高于if语句:
原因在于:switch语句在运行时,首先会生成一个“跳转表”来指示实际的case分支的地址,而这个“跳转表”的索引号与swtich中的case值是相等的,这样的话,switch就不用像if else那样,遍历所有的条件,直至找到正确条件,而仅仅只需要访问对应索引号的表项就可以到达定位分支的目的。
简单的说,switch会生成一个数据统计表,将case后面的值全部统计起来,匹配时先拿表中的数据进行比较,如果有则直接跳转到相应case语句;如果没有,则直接跳转到default语句。
那if else呢?其实刚刚我们已经简单的说了其工作流程,这里再次说明一下:
if else语句需要一条一条的去进行取值范围的判断,直到找到正确的选项位置,这样的话势必会浪费大量的时间。
所以,单从其运行的效率来看,switch语句要更胜一筹。
总结
这里简单的总结一下: 1.switch语句由于它独特的case值判断方式,使其执行效率更高,而if else语句呢,则由于判断机制,导致效率稍慢。
2.到底使用哪一个选择语句,和当前的代码环境有关,如果是范围取值,则使用if else语句更为快捷;如果是确定取值,则使用switch更是一个不错的选择。
所有好的程序都是经过不断思考,不断琢磨,付出努力,最终得以完成的。
题目来源:
https://www.nowcoder.com/practice/4060ac7e3e404ad1a894ef3e17650423?tpId=13&tqId=11155&tPage=1&rp=1&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking
题目描述:
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
代码如下:
方法一:使用额外空间进行字符串追加
public class Solution { public String replaceSpace(StringBuffer str) { StringBuffer sb = new StringBuffer(); char[] charArr = str.toString().toCharArray(); for (int i = 0; i < charArr.length; i++) { if (charArr[i] == ' ') { sb.append("%20"); } else { sb.append(charArr[i]); } } return new String(sb); } } 方法二:
在当前字符串替换,怎么替换才更有效率(不考虑java里现有的replace方法)。
从前往后替换,后面的字符要不断往后移动,要多次移动,所以效率低下
从后往前,先计算需要多少空间,然后从后往前移动,则每个字符只为移动一次,这样效率更高一点。
public class Solution { public String replaceSpace(StringBuffer str) { int spacenum = 0;//spacenum为计算空格数 for (int i = 0; i < str.
大家好,我是烤鸭:
今天使用 javax.script.ScriptEngine 遇到一个奇怪的问题,无法识别js方法。
1. 报错内容: javax.script.ScriptException: ReferenceError: "a" is not defined in <eval> at line number 1057 at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:470) ~[nashorn.jar:na] at jdk.nashorn.api.scripting.NashornScriptEngine.invokeImpl(NashornScriptEngine.java:392) ~[nashorn.jar:na] at jdk.nashorn.api.scripting.NashornScriptEngine.invokeFunction(NashornScriptEngine.java:190) ~[nashorn.jar:na] at com.mys.my.wechat.utils.aes.JSSecret.getDatas(JSSecret.java:50) ~[classes!/:1.0.0-SNAPSHOT] at com.mys.my.wechat.WxMpDemoApplication.main(WxMpDemoApplication.java:26) [classes!/:1.0.0-SNAPSHOT] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201] at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48) [wxChat.jar:1.0.0-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:87) [wxChat.jar:1.0.0-SNAPSHOT] at org.springframework.boot.loader.Launcher.launch(Launcher.java:50) [wxChat.jar:1.0.0-SNAPSHOT] at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51) [wxChat.jar:1.0.0-SNAPSHOT] Caused by: jdk.nashorn.internal.runtime.ECMAException: ReferenceError: "a" is not defined at jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:57) ~[nashorn.jar:na] at jdk.
原理 Java远程调试的原理是两个VM之间通过debug协议进行通信,然后以达到远程调试的目的,两者之间可以通过socket进行通信
调试体系JPDA JPDA(Java Platform Debugger Architecture)是 sun 公司开发的 java平台调试体系,它主要有三个层次组成,即 Java 虚拟机工具接口(JVMTI),Java 调试线协议(JDWP)以及 Java 调试接口(JDI)
JVMTI(JVMDI): jdk1.4 之前称为JVMDI,之后改为了JVMTI,它是虚拟机的本地接口,其相当于 Thread 的 sleep、yield native 方法
JDWP(Java Debug Wire Protocol):java调试网络协议,其描述了调试信息的格式,以及在被调试的进程(server)和调试器(client)之间传输的请求
JDI:java调试接口,虚拟机的高级接口,调试器(client)自己实现 JDI 接口,比如 idea、eclipse 等
下面使用两张图更直观的了解JPDA的三个模块层次
1、JPDA模块层次
2、JPDA层次比较
idea 或者 eclipse 调试原理 当我们在 idea 或者 eclipse 中以 debug 模式启动运行类,就可以直接调试了,这其中的原理令人不解,下面就给大家介绍一下
客户端(idea 、eclipse 等)之所以可以进行调试,是由于客户端 和 服务端(程序端)进行了 socket 通信,通信过程如下:
1、先建立起了 socket 连接
2、将断点位置创建了断点事件通过 JDI 接口传给了 服务端(程序端)的 VM,VM 调用 suspend 将 VM 挂起
3、VM 挂起之后将客户端需要获取的 VM 信息返回给客户端,返回之后 VM resume 恢复其运行状态
世界国家geojson大全,各国地图json数据下载
转载于:https://www.cnblogs.com/firstcsharp/p/11309393.html
这个是把第n位挤到后一位
#include<stdio.h> #include<string.h> #include<stdlib.h> char *change(char s1[],char s2[],int n) { int len1=strlen(s1); int len2=strlen(s2); int i; int j=0; int k=0; for(i=len1-1;i>=n-1;i--) //因为插入多少长度的字符串总长度就会增加多少长度 { //所以先补齐后面的字符元素先 s1[i+len2]=s1[i]; } for(i=0;i<len2;i++) //在第n位的上面插入字符串,而第n为后面接上 s1[n-1+i]=s2[i]; return s1; } int main() { char s1[]="abcd" ; char s2[]= "qwe"; int n=3; //第三位 char s3[30]; char *newstr = s3; newstr = change(s1, s2, n); printf("%s\n", newstr); } 这个是在第n为后面插入
#include<stdio.h> #include<string.h> #include<stdlib.h> char *change(char s1[],char s2[],int n) { int len1=strlen(s1); int len2=strlen(s2); int i; int j=0; int k=0; for(i=len1-1;i>=n-1;i--) { s1[i+len2]=s1[i]; } for(i=0;i<len2;i++) //在第n位的后面插入 s1[n+i]=s2[i]; return s1; } int main() { char s1[]="
InnoDB 引擎数据存储 要想了解数据库 InnoDB 引擎是怎么样存储数据的,必须先了解 B+Tree,了解之后才容易理解其存储原理
在 InnoDB 存储引擎中,也有页的概念,默认每个页的大小为 16K,也就是每次读取数据时都是读取 4*4K 的大小。
一般表的主键类型为INT(占用4个字节)或BIGINT(占用8个字节),指针类型也一般为4或8个字节,也就是说一个页(B+Tree中的一个节点)中大概存储16KB/(8B+8B)=1K个键值(因为是估值,为方便计算,这里的K取值为 10^3)。也就是说一个深度为3的B+Tree索引可以维护10^3 * 10^3 * 10^3 = 10亿 条记录。
实际情况中每个节点可能不能填充满,因此在数据库中,B+Tree的高度一般都在2~4层。mysql的InnoDB存储引擎在设计时是将根节点常驻内存的,也就是说查找某一键值的行记录时最多只需要1~3次磁盘I/O操作
假设我们现在有一个用户表,我们往里面写数据,如下图:
注意:在某个页内插入新数据时,为了减少数据的移动,通常是插入到当前行的后面或者是已删除行留下来的空间,所以在某一个页内的数据并不是完全有序的。为了数据访问的顺序性,每条记录中都有指向下一条记录的指针,以此构成了一个有序的链表
由于只有10条记录,可以放在同一页 page1上,如果每页只能存放10条记录,当第 11 条记录插入时,数据是怎么存放的呢?如下图:
存储过程如下:
1、创建新页 page2,将 page1 的数据复制到 page2上
2、创建新页 page3,将新数据插入到 page3中
3、原来的 page1 还作为根节点,但是变成了一个只存放索引(11)不存放数据的页了,它有两个子节点 page2 和 page3
这里有以下两个问题
1、为什么要复制 page1 数据到 page2 而不是创建一个新的 page1 作为根节点 ,原来的 page1 成为 page2,这样子就减少了数据复制开销?
如果是创建新的 page1 为根节点的话,其存储的物理地址可能会变,在 InnoDB 引擎中根结点是会预读到内存中的,如果根节点的地址变了,不利于数据查找了
2、插入第 11 条数据之后,节点裂变了,根据 B+Tree 的特性,它至少是 11 阶,而裂变之后每个节点的元素至少为 11/2 = 5个,那么数据分布应该是 1-5 key的数据放到 page2 中,6-11 key的数据放到 page3 中,根节点存放主键 key 6呢?
文章目录 前言正文原题题目大意思路1思路2思路3 总结 前言 今天的题是一道简单难度的,建议大家看完题目之后,至少想到两三种解决方法,有助于更好的掌握。
正文 原题 链接:旋转数组
Given an array, rotate the array to the right by k steps, where k is non-negative.
Example 1:
Input: [1,2,3,4,5,6,7] and k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]
Example 2:
Input: [-1,-100,3,99] and k = 2
Output: [3,99,-1,-100]
Explanation:
rotate 1 steps to the right: [99,-1,-100,3]
保存:(write_hw_ila_data + 路径 + [upload_hw_ila_data hw_ila_*])
write_hw_ila_data F:/work/17_vpss_debug/vid_vpss_vpm/top.srcs/sources_1/ila/fpga_wr_wave [upload_hw_ila_data hw_ila_4]
读取:(read_hw_ila_data + 路径)
read_hw_ila_data F:/work/17_vpss_debug/vid_vpss_vpm/top.srcs/sources_1/ila/fpga_wr_wave.ila
显示:
display_hw_ila_data
1、在虚拟机VMWare中安装CentOS7操作系统,并使用XShell连接CentOS操作系统
2、从MySQL官网中下载MySQL5.7压缩包
3、在XShell中使用命令rz上传MySQL5.7压缩包到CentOS7系统中
4、解压缩安装包
5、安装rpm文件
6、删除/var/lib/mysql目录,启动mysql数据库,并查看mysql数据库状态
7、查找root初始密码并登录
刚安装的mysql,root用户是具有初始密码的,保存在文件 /var/log/mysqld.log中。我们需要查得root用户的初始密码,再进行登录:
8、修改root密码
mysql5.7中的默认密码规则,不允许设置的密码太简单。
MySQL完整的初始密码规则可以通过如下命令查看: mysql> SHOW VARIABLES LIKE 'validate_password%';
通常情况下,我们可以修改密码规则,使用较简单的密码,命令如下下图:
注意:在MySQL8的版本中,这两个变量变为: validate_password.policy 和 validate_password.length 。
9、开放mysql的远程连接
默认情况下,MySQL服务安装完成后,只可使用本机上的客户端进行连接。如果需要在其他电脑上连接,则需要开放root用户的远程连接功能,操作如下图:
10、设置CentOS的防火墙,使端口3306通过防火墙
CentOS系统中如果开启了防火墙,那么,在其他电脑上的客户端是连接不到CentOS系统中的MySQL服务器的,原因是防火墙拦截了3306端口的通信。可使用下面命令将3306端口加入到防火墙中,并重启防火墙:
关于防火墙的其他命令,请参考:Centos7允许3306端口通过防火墙
完成以上操作后,可以使用SQLyog远程连接数据库,至此,完成在CentOS7中离线安装MySQL5.7。
文章目录 背景及应用基础及计算卷积池化感受野 卷积神经网络的定义bvb CNN在pytorch中的实现**卷积**:**池化**: 标准化数据预处理Batch Normalization 有名的卷积网络结构AlexNetpytorch实现 **VGG**pytorch实现 GoogLeNetpytorch实现 ResNetpytorch实现 DenseNetpytorch实现 卷积神经网络训练技巧数据增强学习率衰减Dropout正则化微调进行迁移学习灵活的数据读取ImageFolderDatasetDataLoadercollate_fn 批标准化pytorch实现 TensorBoard可视化 背景及应用 基础及计算 因为是彩色图片,所以有RGB三个通道。
传统方法处理图像
卷积 引入卷积
十字架元素不等于零。
卷积运算
左边的矩阵是输入图像抽取的一部分,表示每一个像素点的像素值。
卷积运算
到
运算规则
卷积
扩充0来增加卷积输出的大小:
以上输出矩阵从4×4到6×6,还可以保留边缘信息。原本边缘信息只能用到一次,用这个方法可以用到很多次。
我们在矩阵外部补零的时候可以补很多层0,称这个层数为“padding”
卷积输出后矩阵大小的计算公式(以宽度为例)
W o u t = ( W − K + 2 P ) / S + 1 {W_{out}} = (W - K + 2P)/S + 1 Wout=(W−K+2P)/S+1,有小数,则向下取整。
卷积层
比如:输入(32,32,3)的矩阵,有6个(5,5)卷积核。
那么我们就有5个(28,28)输出矩阵,连接起来就是(28,28,6)的输出
总结
池化 找最大值输出:最大值池化
统计平均值信息:均值池化
池化的作用
计算公式和卷积一样,但如果有小数,向上取整。
感受野 感受野计算时有下面几个知识点需要知道:
问题重述 一个慢跑者在平面上按如下规律跑步: X=10+20cost, Y=20+15sint。突然有一只狗攻击他,这只狗从原点出发,以恒定速率跑向慢跑者,狗的运动方向始终指向慢跑者。分别研究w=20,w=5时狗是否能追上慢跑者;如果能追上,求所用的时间,画出狗与慢跑者之间距离的变化曲线。
问题分析 本文将问题看作追及问题,根据狗与人的位置关系建立微分方程。由于狗从原点出发以恒定速率跑向慢跑者并且狗的运动方向始终指向慢跑者,故问题可以看作狗与人始终在同一直线段的追及问题。
假设时刻t时,人的坐标为(X(t),Y(t)),狗的坐标(x(t),y(t))。分解狗的速度,此时有:
由于狗从原点出发以恒定速率跑向慢跑者并且狗的运动方向始终指向慢跑者,因此可以将问题看作狗在x,y两个方向上对人的追及问题。分别建立狗x,y关于t的方程,可得微分方程组:
最后将已知条件带入方程组可得狗的运动轨迹方程:
求解结果 通过计算结果可以知道,当w=20时狗能追上慢跑者,而w=5时并不能追上慢跑者。当w=20时,求解出t=4.188时狗正好能追上慢跑者,此时的轨迹图为:
clean code
代码整洁之道
clean code: 能够实现功能,重复代码少,抽象合理有层次,代码表达力高,易于维护/修改/扩展
chapter 2 命名
统一的命名规范
清晰、有意义的名字
chapter 3 函数
短小,只做一件事
每个函数一个抽象层级
使用描述性的名称
函数参数数量尽可能的少
无副作用
使用异常替代返回错误码
别重复自己
chapter 4 注释
尽量用代码来阐述
好的注释:提供有效的信息 比如法律信息,意图的说明,警示/强调,todo
chapter 5 格式
团队统一的格式
变量声明尽量靠近其使用位置
相关函数互相靠近
chapter 6 对象和数据结构
对象把数据结构隐藏在抽象之后,暴露操作数据的函数
数据结构暴露数据,不提供有意义的函数
面向过程式代码便于在不改动数据结构的前提下添加新函数,面向对象的代码便于在不改动既有函数的前提下添加新类。
添加新的数据类型,使用面向对象的方式更方便,不影响其他的对象。
添加新的行为,使用面向过程的方式更方便,不印象其他的行为。
chapter 7 错误处理
使用异常而非返回错误码
使用unchecked error
给出详细的error message
依据调用者的需要定义异常类,打包/封装第三方异常信息抛出自己的异常
不要返回/传递null值
checked error
unchecked error
Exception分为一般的Exception和RuntimeException两类。
RuntimeException(Unchecked)继承Exception(Checked)接口。
继承RuntimeException的异常为unchecked exception。不需要声明抛出异常。
RuntimeException及其子类,如:OutOfMemoryError, UndeclaredThrowableException, IllegalArgumentException, IllegalMonitorStateException, NullPointerException, IllegalStateException, IndexOutOfBoundsException等。
继承Exception的异常为checked exception。必须显式声明抛出异常。
chapter 8 边界
cpu中(cache或寄存器)或DDR中或flash中的 一个或者多个bit发生位反转如0变为1,1变为0.这样的变化没有软件参与,是硬件自己变的
问题描述:
将字符串原地压缩,如"eeeeeaaaffeee"压缩为"e5a3f2e3",请编程实现 代码展示:
public static void main(String[] args) { Scanner sc=new Scanner(System.in); System.out.println("请输入字符串"); String s=sc.nextLine(); int[] a=new int[s.length()+1]; for (int i = 0; i <s.length(); i++) { a[i]=s.codePointAt(i);//将字符的Unicode存在a数组里 } int count=1; for (int i = 1; i <a.length; i++) { if (a[i]==a[i-1]){ count++; }else { System.out.print((char)a[i-1]+""+count);//字符与int相加时会自动转为int,所以用字符串拼接一下 count=1; } } }
以下为微信小程序font-family中提供的十四种字体 如果同时设置font-size,有时会对font-family的效果产生干扰,导致字体设置无效,需注意字体大小问题。
字体一 font-family:‘Courier New’, Courier, monospace;
字体二 font-family:‘Franklin Gothic Medium’, ‘Arial Narrow’, Arial, sans-serif;
字体三 font-family:‘Gill Sans’, ‘Gill Sans MT’, Calibri, ‘Trebuchet MS’, sans-serif;
字体四 font-family:‘Lucida Sans’, ‘Lucida Sans Regular’, ‘Lucida Grande’, ‘Lucida Sans Unicode’, Geneva, Verdana, sans-serif;
字体五 font-family:‘Segoe UI’, Tahoma, Geneva, Verdana, sans-serif;
字体六 font-family:‘Times New Roman’, Times, serif;
字体七 font-family:‘Trebuchet MS’, ‘Lucida Sans Unicode’, ‘Lucida Grande’, ‘Lucida Sans’, Arial, sans-serif;
字体八 font-family:-apple-system, BlinkMacSystemFont, ‘Segoe UI’, Roboto, Oxygen, Ubuntu, Cantarell, ‘Open Sans’, ‘Helvetica Neue’, sans-serif;
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:armink.ztl@gmail.com】
项目原始 GitHub 地址:https://github.com/armink/HackSTLinkUpgrade
背景 一些 ST-Link 在使用最新的 IDE 时,经常提示需要升级其固件,但是升级始终失败,提示容量不足。
在 Keil MDK 上可能就提示一下升级失败,但仍然可以继续下载调试。可是当使用 ST 最新推出的 CubeIDE 时(这是一款 ST 新推出的基于 Eclipse 集成 CubeMX 的 IDE),情况就非常糟糕,你如果不升级成功,就没法让你继续使用,仿佛陷入了死循环,导致一些开发板完全无法使用 CubeIDE。
问题原因 这些开发板包括 RT-Thread 和 正点原子 联合推出的 潘多拉 IoT 开发板 。
该开发板上的 ST-Link 用的是 STM32F103C8T6 ,C8T6 只有 64KB flash,在早期 ST-Link 固件比较小的时候,64KB 完全是够用的。但随着 ST-Link 的功能升级后,固件大小正好超过了 64KB ,导致了现在提示的升级错误,如下图所示。提示信息为:The up-to-date firmware is too big for this board (4960 bytes in excess). Can't update。就差这么 4K 多的空间了。
1、创建eureka报错 There is no known eureka server; cluster server list is empty
没有已知的Eureka服务器;群集服务器列表为空
需要设置自己注册自己就不会报错
2、
registerWithEureka: false
fetchRegistry: false
本教程适用于以下网关烽火HG261GS。
发现网上的一些教程已经失效,现发现获取网关的超级密码并不是一件难事,当然是截止到当前文案的时间啦~
本教程纯属原创,如需转载请注明原链接
获取加密的密码
我们直接打开:http://192.168.1.1/cgi-bin/baseinfoSet.cgi,执行出来的结果中有几下几行
"baseinfoSet_TELECOMACCOUNT":"telecomadmin", "baseinfoSet_TELECOMPASSWORD":"120&105&112&105&103&115&113&101&104&113&109&114&57&53&48&55&53&51&55&55&", "baseinfoSet_USERACCOUNT":"useradmin", "baseinfoSet_USERPASSWORD":"75&84&76&86&81&", 我们得到了加密的超级密码(baseinfoSet_TELECOMACCOUNT),我们发现其非常的规整。
我们试着将中间的"&"取下,得到加密的密码
转换密码
除下我们得到的加密的管理员密码,我们发现还有普通用户(baseinfoSet_USERACCOUNT)的加密的密码。我们将网关背面的普通用户密码与加密的密码对对应:
我们便可以得到以下规律:
字母对应的ASCII = 加密数字 -4
接下来我们来试试超级管理员密码,得到以下的结果
我们将得到的密码:telecomadmin51,31/33(账号为telecomadmin)填入,发现密码错误。
我们再思考,前面的加密密码转换后得到的是telecomadmin,逻辑上感觉没错,但是后面翻译的好像不对。于是我们将ASCII码直接转换(不减4),得到了telecomadmin95075377,填入,发现进入了终端,搞定!
总结
加密算法:字母转换为其ASCII码+4,数字直接就是ASCII码
文章目录 一、Tensorflow模型二、保存模型三、模型数据的读取四、其他保存和读取方法 在深度学习中,经常会听到”预训练“、”保存模型“、”加载模型“等词,实际上就是在模型训练完成之后,将模型及其训练得到的参数保存下来,下次再来直接调用,或者上次得到的数据上再次训练(预训练)。
一、Tensorflow模型 所谓的Tensorflow模型,是指训练得到的网络参数的网络设计或图形和值。因此,Tensorflow模型有两个主要的文件:
Meta graph:这是一个协议缓冲区,它保存了完整的Tensorflow图形;即所有变量、操作、集合等。该文件以.meta作为扩展名,如下: model.ckpt.meta Checkpoint file::这个文件是以.ckpt为后缀的,是个二进制的文件,里面保存了.meta文件中对应变量或者tensor或者操作等等的值。但是现在变成了三个文件,分别是以.index 和.data为后缀的两个文件加上一个checkpoint文件。其中.data文件保存了我们训练的变量的值;checkpoint 文件仅仅记录最新保存的模型是哪个,如下: checkpoint model.ckpt.data-00000-of-00001 model.ckpt.index 二、保存模型 在深度学习中,往往训练需要很长的时间,而每次要用模型的时候不可能重新在训练一次,所以要把模型保存起来。在tensorflow中如果想保存graph和参数的值,我们需要用到tf.train.Saver() ,演示代码如下:
#################保存模型################ # 执行本段程序时注意当前的工作路径 import tensorflow as tf v1 = tf.Variable(tf.constant(1.0, shape=[1]), name="v1") v2 = tf.Variable(tf.constant(2.0, shape=[1]), name="v2") result = v1 + v2 saver = tf.train.Saver() with tf.Session() as sess: sess.run(tf.global_variables_initializer()) saver.save(sess, "Model/model.ckpt") 将定义的float32型的2*3的矩阵保存在当前路径的"Model"文件夹中,4个文件如下:
三、模型数据的读取 现在开始读取上一步保存的模型参数。有两种方法:
1)、自己写一个一模一样的网络出来,如下:
#########加载方法一: #重新定义相同的dtype和shape import tensorflow as tf v1 = tf.Variable(tf.constant(1.0, shape=[1]), name="v1") v2 = tf.Variable(tf.constant(1.0, shape=[1]), name="
1.在Cortana(dell为例)内输入命令提示符 5个字
2.右键以管理员身份运行
3.输入slmgr.vbs -skms zh.us.to
回车后继续输入 slmgr /ipk Windows密钥
(Windows密钥可以在自己笔记本上查询,具体步骤参考
我的另一篇博客—如何查找自己笔记本的产品密钥
注意:也可以在网上找一个密钥,完全可以正常激活。
回车后输入slmgr /ato
成功激活windows!
一.写在前面 最近做完直播的基础功能后,又多了很多相关的需求,其中有一个就是直播间分享榜单的功能,顾名思义就是:分享本直播间并成功拉用户进来的数量做一个排行。比如我分享了这个直播间,别人通过我分享的直播间链接点进来,那么这个人就是我邀请来的,我总共邀请了10个人,你总共邀请了6个人,他总共邀请了11个人。实时排名就是他>我>你。简单介绍了一下功能,其实就是个根据某个权重值做排行榜的功能。 二.介绍redis的zset 这里就不说具体的zset实现了(我太菜,不敢放肆,等我牛逼了我再写zset实现,估计n年后 ),总之为了速度和稳定性以及持久化,redis肯定是最合适的,而且redis又有zSet这种数据结构,那不用zSet岂不是浪费嘛。
首先简单说一下zSet:
Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。
(这么专业的话我肯定是说不出来的,当然是网上找的啦) 命令描述ZADD key score1 member1 [score2 member2]向有序集合添加一个或多个成员,或者更新已存在成员的分数ZCARD key获取有序集合的成员数ZCOUNT key min max计算在有序集合中指定区间分数的成员数ZINCRBY key increment member有序集合中对指定成员的分数加上增量 incrementZINTERSTORE destination numkeys key [key …]计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中ZLEXCOUNT key min max在有序集合中计算指定字典区间内成员数量ZRANGE key start stop [WITHSCORES]通过索引区间返回有序集合成指定区间内的成员ZRANGEBYLEX key min max [LIMIT offset count]通过字典区间返回有序集合的成员ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT]通过分数返回有序集合指定区间内的成员ZRANK key member返回有序集合中指定成员的索引ZREM key member [member …]移除有序集合中的一个或多个成员ZREMRANGEBYLEX key min max移除有序集合中给定的字典区间的所有成员ZREMRANGEBYRANK key start stop移除有序集合中给定的排名区间的所有成员ZREMRANGEBYSCORE key min max移除有序集合中给定的分数区间的所有成员ZREVRANGE key start stop [WITHSCORES]返回有序集中指定区间内的成员,通过索引,分数从高到底ZREVRANGEBYSCORE key max min [WITHSCORES]返回有序集中指定分数区间内的成员,分数从高到低排序ZREVRANK key member返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序ZSCORE key member返回有序集中,成员的分数值ZUNIONSTORE destination numkeys key [key …]计算给定的一个或多个有序集的并集,并存储在新的 key 中ZSCAN key cursor [MATCH pattern] [COUNT count]迭代有序集合中的元素(包括元素成员和元素分值) 上面就是redis的zset相关的命令,项目中实际是不会这么写的,我们使用的RedisTemplate进行的redis操作
首先我们知道RedisTemplate类可以操作五种数据类型,分别为string,list,hash,set,zset,本次我主要说一下我操作list时所遇到的坑.如果在同一个项目中直接存储对象是没有问题的,无论是序列化还是反序列化都没有问题,但是一旦另外一个项目需要获得这个缓存中的数据就会发现反序列化失败,究其原因就是说不同项目之间没有用相同的序列化方式,那么我们只需要在项目之间采用相同的序列化方式就可以,代码如下,将下述代码放如入启动类下面即可
@Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 使用Jackson2JsonRedisSerialize 替换默认序列化 @SuppressWarnings("rawtypes") Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(objectMapper); // 设置value的序列化规则和 key的序列化规则 redisTemplate.setValueSerializer(jackson2JsonRedisSerializer); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.afterPropertiesSet(); return redisTemplate; } 本以为问题解决了,但是在另外一个项目获取对象的时候,会发现反序列化的时候报找不到对象的错误,通过查看Redis存储的对象信息我们会发现对象序列化的时候把对象相应的包名也存进去了,这就比较坑了,代码实例如下
["com.base.common.entity.User",{"id":0,"username":"哈哈哈","displayName":"hhhhh","mobile":null,"department":null,"mail":null,"status":0,"createTime":null,"lastUpdateTime":null,"isManager":0}] 反序列化的时候根据包名找这个对象当然会找不到,所以我们需要保证多个项目之间用的是同一个对象,那么我们就需要将对象放入公司的仓库中,这样问题就解决了,欢迎大家的批评指正
对于工作几年的开发人员来说,不论是在工作中,还是在面试时,都会涉及到SQL优化的问题。
为什么要进行SQL优化? 1、访问网站时可避免一些错误,例如:
1)连接数据库超时导致页面报5xx错误
2) 因查询过慢导致页面加载缓慢,甚至无法加载
2、增加数据库的稳定性,很多数据库问题都是由于低效的查询引起的
3、使页面的访问更流畅,提升用户体验
哪些方法可以进行SQL优化? 1、SQL语句优化
SQL语句优化,是基础的一种优化方式。
2、主从分离
原因一:对于大部分的应用程序,大部分的操作都是查询(即读数据),小部分的操作是增删改(即写数据)。所以,数据库的大部分压力来自于读操作。当读的压力较大时,我们可以通过读写分离的方式,降低读的压力,提升读取时的效率。
原因二:如果不实现读写分离,所有的数据全部存储于同一个库中,这样,如果因网络问题而连接不到这个库,或者,某些原因导致这个数据库出现故障,那么,所有数据都将丢失。可能会出现单点故障的风险。
3、分表分库
任何一个数据库的存储容量都是有限的,一旦数据量过大,将会导致数据库处理数据的效率急剧下降。所以,我们可以采用分表分库的方式,确保每个库中的数据量在较好的范围内。
此篇文章暂且只介绍SQL语句优化。
SQL语句优化 1、使用索引 , 合理的使用索引,能够大大提升数据的检索效率。
在经常需要做为查询条件的列上,创建索引。 但是,并不是索引越多越好。索引可提高查询效率,但是会降低增删改的效率。因此,一张表中最好不要超过6个索引。
2、慎用 * , 务必使用 字段名代替 * 1) select 后跟需要查询的字段名,不要跟 * select * from stu 数据库执行上面语句时有两步:1、查询stu表中所有的字段 2、根据第一步中查得的字段,查询stu表中的数据
select id, name, age, sex from stu 上面语句将会直接查询stu表中的数据
2) count() 聚合函数中,不要使用 * select count(*) from table ,这会引起全表扫描,并且没有任何业务意义,是一定要杜绝的。
可使用 count(id) 或 count(1) 等替代。
3、慎用 or
如果一个字段有索引,一个字段没有索引,将导致引擎放弃使用索引而进行全表扫描,如:
select id from stu where age=20 or name=’admin’
在项目开发中,经常会需要处理分布式事务。例如数据库分库分表之后,原来在一个单库上的操作可能会跨越多个数据库。系统服务化拆分之后,原来的在一个系统上的操作可能会跨越多个系统。就连我们平时经常使用到的缓存(如redis、memcache等)也可能涉及分布式事务,因为缓存和数据库是两个不同的实体,如何保证数据在缓存和数据库间的一致性也是要重点考虑的。分布式事务就是指事务要处理的资源分别位于分布式系统中的不同节点之上的事务。
对于单机系统,通常我们借助数据库实现本地事务,例如下面JDBC代码实现了一个事务:
由于在分布式系统中,多个系统无法共用同一个数据库链接,所以无法简单借用上面的处理方式实现分布式事务。
下面将介绍几种本人在实际开发中使用过的处理分布式事务的方式,最后再引出分布式事务的相关理论并进行总结。
避免出现分布式事务 由于分布式事务比较难于处理,所以应该尽量避免分布式事务的发生。例如对于一个客户信息系统,由于注册用户数太多导致存储的数据量过大,所以对其进行分库分表存储。而客户信息模型又分为多个子模型,对应数据库中的多个表,例如客户基本信息表、客户登录账号表、客户登录密码表、客户联系方式表等等。假设登录账号表和客户基本信息表的关联关系如下所示:
user_id和login_id分别是两个表的主键,user_id还作为login_info表的外键使两个表关联。在用户注册时会自动生成user_id和login_id的值。user_info和login_info两个表分别采用user_id和login_id计算分库分表规则。假设我们对每个模型分十库一百表存储,即存在user_info_00 ~ user_info_99一百个表,其中user_info_00 ~ user_info_09属于第一个库,user_info_10 ~ user_info_19属于第二个库,依次类推。
在分库分表之后,如果我们不仔细考虑user_id和login_id的生成规则(例如随意生成一个数字字符串或简单使用递增sequence),就可能导致同一个用户的user_info信息和login_info信息被分别存储到两个不同的库,这就会导致分布式事务发生。
面对这种问题,最好的解决思路就是考虑如何避免分布式事务的发生。只要想办法让跟一个用户相关的所有模型数据全部存入到一个库中,就可以避免分布式事务了。由于每个模型数据的分库分表路由规则又是由各个表的主键id决定的(例如user_id、login_id),所以只要对各个表的主键生成规则进行定制,就可以保证一个用户的所有模型数据全部存到同一个库。假设有下面的id生成规则:
开始的两位是标识模型位,例如user_id以01开头,login_id以02开头。
接下来的11位是sequence递增序列号,如果想要更多的ID可以扩大这部分的位数,但对于存储用户信息而言,11位的长度足够。
接下来是分库分表位,如果每个模型的分库分表算法都相同,那么只要保证每个模型的主键ID的分库分表位都相同,就能保证一个用户的所有模型数据都会存到同一个库中。
最后一位是id校验位,这一位根据前面15位的内容生成,方便对一个id进行校验。
根据这个思想,我们可以在用户注册的时候先生成user_id,user_id的分库分表位可以随机生成。然后在为其它模型生成主键id时(例如login_id),必须让这个模型的主键id的分库分表位与user_id的分库分表位相同。另外一点也要注意,一个表的查询条件不一定只有主键id一个,如果有其它查询条件列,那就要保证那一列的生成规则也要包含相同的分库分表位,否则就不能使用该列进行查询。
通过这种方式,就可以保证一个用户的所有模型数据全部存储到同一个库中,有效的避免分布式事务的发生。
事务补偿 通常情况下,应对高并发的一个主要手段就是增加分布式缓存(如redis)以提高查询性能。增加分布式缓存后系统查询数据的流程如下图:
即先尝试从缓存中查询数据,如果缓存命中就直接返回结果,否则尝试从DB中查询数据。如果查询DB命中则将数据补充到缓存,以便下次查询时可以命中缓存。
而在更新数据时,通常是先更新DB中的数据,DB写入成功后再更新缓存中的数据。那么就有一个问题,如何保证缓存和DB间数据的一致性?由于缓存和DB是两个不同的实体,写入DB成功后再去更新缓存,如果缓存更新失败(例如网络抖动造成短暂的缓存不可用)就会造成缓存和DB的不一致。此时按照上图的查询逻辑,先查缓存就会查询到“脏”的数据,就会严重影响业务。这也是一个典型的分布式事务问题——缓存和DB要嘛同时更新成功,要嘛同时更新失败。解决这个问题的一个较好方式就是事务补偿。
我们可以在DB中创建一张事务补偿表transaction_log,transaction_log表可以和业务数据在一个库中,也可以在不同的库。在更新数据前,先将要更新的模型数据记录到transaction_log中。例如我们更新user_info表中的数据,就将userId记录到transaction_log中。
transaction_log记录成功后,再去更新业务数据表user_info中的内容,最后更新缓存中的userInfo数据。缓存更新成功后,就可以删除transaction_log表中对应的记录。
假设在更新完user_info表之后,由于网络抖动等原因导致缓存更新失败,则transaction_log表中对应的记录就会一直存在,表示这个事务没有完成的一种记录。
应用会创建一个定时任务,周期性的扫描transaction_log表中的记录(例如每隔2S扫描一次)。发现有符合条件的记录,就尝试执行补偿逻辑。例如更新用户信息时,DB中的user_info表更新成功,但缓存更新失败,定时任务发现transaction_log表中对应的记录没有删除且已经超过正常等待时间,就尝试使缓存和DB一致(可以删除缓存中对应的数据,也可以根据userId重新查询DB再补充的缓存)。补偿任务执行完成后,就可以删除transaction_log表中对应的记录。如果补偿任务执行再次失败,就保留transaction_log表中的记录,等待下个周期再次执行。
事务补偿这种方式保证的是事务的最终一致性,即如果发生意外,会存在一个时间窗口(例如2S),在这个窗口内DB和缓存间是不一致的,但能保证最终两者的数据是一致的。至于定时任务周期的设定,要结合业务对“脏”数据的敏感程度以及系统的负载能力。
事务型消息 对于一个金融系统,假设有一个需求是用户注册成功后自动为用户创建一个账户。客户的信息维护在客户中心系统,客户的账户信息维护的账务中心系统,如果用户注册成功,必须保证客户的账户在账务系统创建成功。这显然也是一个分布式事务问题。
处理这个问题,显然也可以采用上一小节介绍的事务补偿机制来处理。但注册和开户并不要求一定是同步完成,且需要感知用户注册成功事件的系统并不只有账务系统一个(例如营销系统可能也需要感知用户注册成功的事件,给用户发优惠券),所以使用消息机制异步通知更加合适。那么问题就变成了“如果用户注册成功,一定要保证消息发送成功”。
应对这种场景,可以使用事务型消息。但前提条件是使用的MQ中间件必须支持事务型消息,比如阿里的RocketMQ。目前市面上其它一些主流的MQ中间件都不支持事务型消息,比如Kafka和RabbitMQ都不支持。
下面的序列图是事务型消息的执行流程:
相比于普通消息,发布者发送消息后,MQ并不是马上将消息发送给订阅者,而仅仅是将消息持久化存储下来。
发送消息成功之后,发布者执行本地事务。例如我们例子中提到的用户注册。
根据本地事务执行是否成功,发布者决定对之前已经发送的消息是commit还是rollback。如果是rollback,MQ会删除之前存储的消息。假设我们这里发送commit。
MQ接收到发布者发送的commit后,才会将消息发送给订阅者。之后,就可以利用MQ的消息可靠传输特性促使订阅者完成剩余事务操作,例如上面例子中提到的开户操作。
细心的小伙伴会发现,如果在上图中的第5步发生问题导致发送commit失败,不还是会导致消息发布者和消息订阅者间事务的不一致吗?为了防止这种情况的发生,增加MQ超时回调机制。
下面的序列图是事务型消息commit失败时的执行流程:
当MQ长时间收不到发布者的commit/rollback通知时,MQ会回调发布者应用询问本地事务是否执行成功,是commit还是rollback之前的消息。发布者需要提供对应的callback,在callback中判断本地事务是否执行成功。
TCC两阶段提交 在某些场景下,一个分布式事务可能会涉及到多个参与者,且每个参与者需要根据自己当时的状态对事务进行响应。
假设这样一个场景,一个电商网站可以允许用户在支付时选择多种支付方式。例如总共需要支付100元钱,用户可以选择积分支付10元,账户余额支付90元。用户的积分由营销系统负责,账户余额由账务系统负责,订单的状态管理由订单系统负责。
首先,要先确保事务的各个参与者满足条件才能执行事务。例如积分系统要确保用户的积分超过10元钱,账务系统要确保用户的账户余额大于90元钱才能发起这次交易。
其次,就是要满足事务的原子性。这里的用户积分、用户余额、订单状态,要嘛全部处理成功,要嘛全部保持不变。
应对这种分布式事务场景,可以采用TCC两阶段提交的方式进行处理。关于TCC的详细描述,大家也可以参考下这篇博文,我觉的讲的很好。
TCC将整个事务分成两个阶段——try和commit/cancel。TCC整个流程具有三种角色——事务发起者、事务参与者、事务协调者。以上面的订单支付为例,采用TCC实现处理事务的流程如下:
第一阶段try,订单系统分别调用promotion和account两个系统,询问该用户是否有足够的积分和账户余额。为了防止资源争抢,在这个阶段会对资源进行锁定,即营销系统会锁住用户的10元积分,账务系统会锁住用户的90元账户余额。
如果在try阶段有任何一个参与者处理失败(例如用户积分不够10元或者用户的余额不够90元),则事务发起方(订单系统)会通知事务协调组件,后者会通知所有的事务参与者cancel在try阶段锁定的资源。
如果在try阶段所有的参与者都处理成功,则事务发起方通知协调者commit这个事务,协调者会通知所有的参与者完成事务的commit。这时系统会完成真正的余额和积分扣减。2.2步是假设订单系统也要更新订单的状态。
但仅是这样处理还是有一致性问题,例如在第二阶段commit时如果发生宕机、网络抖动等异常情况,就可能导致事务处于“非最终一致”状态(参与者只执行了try阶段,没有执行第二阶段。或部分参与者第二阶段commit成功,部分参与者commit失败)。为了应对这种情况,需要增加事务日志,以便发生异常时恢复事务。
可以利用DB这种可靠存储来记录事务日志。日志中应包含事务执行过程中的上下文、事务执行状态、事务的参与者等信息。事务日志可以由事务发起发负责记录,也可以交由事务协调方进行记录。
事务日志可以由主事务记录日志和从事务记录日志组成:
主事务记录日志用于记录事务发起方信息以及事务执行的整体状态。
从事务记录日志用于记录所有的事务参与者信息,以及每个参与者所属的从事务的执行状态。与主事务记录日志是一对多的关系。
有了事务日志后,就可以周期性的不断扫描事务日志,找到异常中断的事务。根据事务日志中记录的信息,推动剩余的参与者commit或者cancel,以便使整个分布式事务达到“最终一致性”。
下面是commit阶段发生异常时的事务补偿逻辑:
TCC两阶段提交的实现需要注意如下事项:
事务中的任何一个参与者都要确保在try阶段操作成功,在第二阶段就一定能commit成功。
参与者在实现commit和cancel接口时要考虑幂等,对重复的commit/cancel请求要能够正确处理。
业务上要考虑对两阶段中间状态(一阶段已完成,二阶段未开始)的处理。一般可以通过一些特殊文案,比如显示当前被冻结的账户余额。
对于状态型数据,当多个事务共同操作同一个资源时,要确保资源隔离。例如账户余额,确保不同的事务操作的金额是隔离的,彼此互不影响。
由于网络丢包、乱序等因素的影响,可能会导致参与者接收到一阶段try请求后,永远收不到commit/cancel请求,导致参与者的资源一直被锁定,永远不会被释放,这种情况叫做事务悬挂。为了防止事务悬挂的发生,可以在第一阶段try成功后,指定一个最大等待时间。超过这个最大等待时间就自动释放被锁定的资源。
总结 传统的单机事务应满足A(原子性)、C(一致性)、I(隔离型)、D(持久性)四个特性,属于刚性事务。由于分布式系统具有多个节点的特点,要求完全满足ACID这四个规范会非常的困难。所以就诞生了柔性事务BASE理论(Basic availability、Soft state、Eventual consistency)。
tushare接口get_realtime_quotes,今天报错了:
AssertionError: 33 columns passed, passed data had 34 columns
看了一下源码,在获取股票代码为600063时,报了错。
dataframe5 = ts.get_realtime_quotes('600063') 与正常的代码比较
dataframe5 = ts.get_realtime_quotes('000001') 定位是在list转换成dataframe是出错了。
df = pd.DataFrame(data_list, columns=ct.LIVE_DATA_COLS) 其中,LIVE_DATA_COLS的定义是有33个元素:
LIVE_DATA_COLS = ['name', 'open', 'pre_close', 'price', 'high', 'low', 'bid', 'ask', 'volume', 'amount', 'b1_v', 'b1_p', 'b2_v', 'b2_p', 'b3_v', 'b3_p', 'b4_v', 'b4_p', 'b5_v', 'b5_p', 'a1_v', 'a1_p', 'a2_v', 'a2_p', 'a3_v', 'a3_p', 'a4_v', 'a4_p', 'a5_v', 'a5_p', 'date', 'time', 's'] 报错是,data_list的值:
"皖维高新,3.060,3.090,3.050,3.090,3.030,3.050,3.060,15402659,47026593.000,86945,3.050,229700,3.040,345100,3.030,430300,3.020,412000,3.010,274500,3.060,538593,3.070,224300,3.080,190700,3.090,295800,3.100,2019-08-01,15:00:00,00,"; 正常的data_list的值:
"平安银行,14.060,14.130,14.100,14.190,13.940,14.100,14.110,52798128,742308285.200,71100,14.100,64800,14.090,61000,14.080,181435,14.070,676618,14.060,224200,14.110,99100,14.120,103000,14.130,102700,14.140,148346,14.150,2019-08-01,15:00:03,00"; 通过对比,很明显,报错时,data_list的值,最后多了一个逗号,dataframe认为有34个元素,比LIVE_DATA_COLS的定义是有33个元素多一个,不匹配,所以报错了。
问题找到了,解决办法有无数个,我选择简单的那个,将data_list只取33个元素:
for index, row in enumerate(data): if len(row)>1: data_list.
nginx负载均衡前端项目 服务器主机名说明10.4.237.123nodea负载主机,负责分发给下面俩服务器10.4.237.124nodeb分发服务1192.168.18.47nodec分发服务2 一、nginx安装(全部服务器执行) 1.1 安装依赖包 yum install gcc yum install -y pcre pcre-devel yum install -y zlib zlib-devel yum install -y openssl openssl-devel yum install wget 1.2 下载nginx安装包 [root@node1 quartz]# cd /usr/local/ [root@node1 quartz]# wget https://nginx.org/download/nginx-1.15.3.tar.gz [root@node1 quartz]# tar -zxvf nginx-1.15.3.tar.gz 1.3 安装nginx //进入nginx目录 [root@node1 quartz]# cd /usr/local/nginx-1.15.3 //执行命令 [root@node1 quartz]# ./configure [root@node1 quartz]# make [root@node1 quartz]# make install [root@node1 quartz]# /usr/local/nginx/sbin/nginx -s reload [root@node1 quartz]# ps -ef | grep nginx //查看nginx进程是否启动: 1.
Java实现 package com.zehin.map.util; public class GPSUtil { public static double pi = 3.1415926535897932384626; public static double x_pi = 3.14159265358979324 * 3000.0 / 180.0; public static double a = 6378245.0; public static double ee = 0.00669342162296594323; public static double transformLat(double x, double y) { double ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.
安装visual stdio 2019的时候,我基本上是安装到D盘的,后来发现D盘莫名其妙多出来一个“Windows kits”,让我这个强迫症难以忍受,于是到网上找教程,发现真的可以移动的。
How to move Windows Kits Folder to other disks?
Try the following technique:
Close all programs, move the “Windows Kits” folder to another disk, for example to “D:\Windows Kits”; remove the original folder.Start the “Command Prompt (Admin)”. It can be found in Start menu. If you find “PowerShell (Admin)”, then start it and execute “cmd”. Then run the command: mklink /J "C:\Program Files (x86)\Windows Kits" "
void merge_sort(int a[], int l, int r){ //只有一个或者没有则不用排序 if(l >= r) return ; int mid = (l + r) >> 1; //取中间值为分界 merge_sort(a, l, mid); //左边区间右边区间进行递归 merge_sort(a, mid + 1, r); int k = 0, i = l, j = mid + 1; while(i <= mid && j <= r){ if(a[i] < a[j]) tmp[k++] = a[i++]; else tmp[k++] = a[j++]; } while(i <= mid) tmp[k++] = a[i++]; while(j <= r) tmp[k++] = a[j++]; //将排好序的数组存回来 //注意这里i是从l到r for(i = l, j = 0; i <= r; i++, j++) a[i] = tmp[j]; } 787.
## 代码模板 void quick_sort(int q[], int l, int r) { if (l >= r) return;// 判断排序的数字长度 int i = l - 1, j = r + 1, x = q[l]; //选取双指针i,j与 中间随机值 while (i < j) { //进行判断比较大小并交换值 do i ++ ; while (q[i] < x); do j -- ; while (q[j] > x); if (i < j) swap(q[i], q[j]); //注意!!!使用语言有没有swap方法(如果没有建议用位运算) else break; } //再将俩个部分(小于等于随机值||大于小于随机值)再次划分 quick_sort(q, l, j),; quick_sort(q, j + 1, r); } 785.
大道至简。html+css+一个简单的JavaScript函数,实现的折叠菜单。
功能:
1.鼠标放置在菜单选项,具有变化;
2.实现一级菜单,二级菜单;
3.一级菜单收起来时,前面是“+”,展开时,前面是“-”;
效果图:
直接贴贴贴代码:
zhedie_menu.html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312" /> <title></title> <style> *{margin:0;padding:0;} div{ font-size:1.5em; color:red; background-color: #dfdfdf; border: 0 solid #1892B5; padding: 0px margin: 0px; } a:link,a:visited { display:block; color:#000000; background-color:#dfdfdf; width:200px; text-align:left; padding:4px; text-decoration:none; } a:hover,a:active { background-color:#dfdfdf; font-weight:bold; } </style> <link href="/static/css/style2.css" rel="stylesheet" type="text/css" /> </head> <body> <script type="text/javascript"> function show(parentid,childid) { var parent = document.getElementById(parentid) var child=document.getElementById(childid); if (child.style.display == "
默认情况,idea 打包不会 把 src/main/java 中的 非class 文件打包进去,
所以 要在pom 的配置文件中加入 配置:
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.yml</include> </includes> <filtering>false</filtering> </resource> </resources> <plugins> </build>
文章目录 前言使用教程第一步 创建项目第二步 加入依赖第三步 配置文件第四步 引导程序第五步 接口开发第六步 启动测试 源码 & 参考 前言 本文介绍Spring Cloud如何通过Nacos作为配置中心
Nacos服务搭建过程略,本文案例使用官网提供的服务,详细信息如下
Nacos控制台 地址 :http://console.nacos.io/nacos/index.html账号/密码 :nacos/nacos 客户端配置 注册中心 :spring.cloud.nacos.discovery.server-addr = console.nacos.io:80配置中心 :spring.cloud.nacos.config.server-addr = console.nacos.io:80 使用教程 第一步 创建项目 创建Maven项目:nacos-spring-cloud-config
第二步 加入依赖 <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> </dependencies> 通过引入spring-cloud-starter-alibaba-nacos-config依赖实现自动配置
第三步 配置文件 通过Nacos Open API创建配置,dataId=spring-cloud-config-nacos.properties,内容为useLocalCache=true
curl -X POST "http://console.nacos.io/nacos/v1/cs/configs?dataId=spring-cloud-config-nacos.properties&group=DEFAULT_GROUP&content=useLocalCache=true" 本地创建bootstrap.properties文件,并加入如下配置
spring.application.name = spring-cloud-config-nacos spring.cloud.nacos.config.server-addr = console.nacos.io:80 默契情况下,应用会请求dataId=${spring.application.name}.properties对应的内容作为配置
第四步 引导程序 @SpringBootApplication public class NacosConfigApplication { public static void main(String[] args) { SpringApplication.
一、概述 Jumpserver是一款由python编写开源的跳板机(堡垒机)系统,实现了跳板机应有的功能。基于ssh协议来管理,客户端无需安装agent。
特点: 完全开源,GPL授权 Python编写,支持再次开发 实现了跳板机基本功能,认证、授权、审计 集成了Ansible。
Jumpserver网络架构图
二、优势 1、完全开源,也可以选择商业支持;
2、支持多种常用的操作系统;
3、提供用户会话记录功能,可以手动终端不明的会话记录;
4、支持录像回放功能,方便生产事故后的问题追溯;
5、所有密码通过系统管理,最终用户不需知道服务器的密码。终结了生产环境密码手工拷贝和传播的方式。
三、安装 官网文档
http://docs.jumpserver.org/zh/docs/dockerinstall.html
博客地址
https://www.cnblogs.com/yanxinjiang/p/8136984.html
https://blog.csdn.net/my_bai/article/details/62226474
windows组件安装
在以下启动guacamole的命令中,JUMPSERVER_SERVER需要是jumpserver的内网ip加端口,仅当端口为80端口时可省略,否则无法向jumpserver发起注册
docker run --name jms_guacamole -d \ -p 8081:8080 -v /opt/guacamole/key:/config/guacamole/key \ -e JUMPSERVER_KEY_DIR=/config/guacamole/key \ -e JUMPSERVER_SERVER=http://172.31.38.9:8080 \ registry.jumpserver.org/public/guacamole:latest 常见问题:
官方常见问题连接:http://docs.jumpserver.org/zh/docs/faq_windows.html
在执行pip install -r requirements.txt命令时有可能因为网络原因导致部分组件无法下载,导致安装失败,可以多尝试几次即可。
使用账号密码访问远程服务器时提示需要安装sshpass,安装命令如下:
apt-get install sshpass Windows登录提示无法连接服务器
系统用户设置时设置为手动登录(自动登录有问题:可能是账号密码写错了)
设置windows文件传输最大限制
vi /etc/nginx/sites-enabled/default location /guacamole/ { proxy_pass http://localhost:8081/; # 如果guacamole安装在别的服务器,请填写它的ip proxy_buffering off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $http_connection; access_log off; client_max_body_size 100m; # Windows 文件上传大小限制 proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } 修改以后重启nginx生效
近期,继外挂之后,和平精英终于开始治理模拟器过检测、手柄等游戏外设了。虽然国际服目前外挂泛滥,但是光子为了保持和平精英游戏环境的干净,一直在治理一切不公平的游戏行为,这点还是值得肯定的:
吃鸡类手游由于需要压枪射击,单纯手搓确实非常不方便,所以除了和平精英,其他吃鸡手游的外挂更是猖狂,这其中的代表就是《荒野行动》跟《王牌战争》,里面的外挂玩家那简直了,都是无敌的存在,普通玩家基本毫无游戏体验感。撇开游戏质量不说,这两游戏凉凉跟外挂有一半的关系!
除了吃鸡类fps游戏,国内的其他游戏外挂还不算太多,特别是跟国外游戏一比,就算你玩个《方舟:生存进化》跟《文明重启》这类末日生存游戏,外挂都不比吃鸡少,可以说国际服简直就是外挂玩家的战斗场!
正常使用模拟器跟手机外设是没有问题,只是系统会给你匹配同类玩家。如果你刻意绕开检测去匹配手机玩家,近期封号几率是很大了,各位慎用!
当然,也有不少玩家用投屏软件把手机投到电脑上再用电脑来控制手机键鼠玩,不过目前仅安卓且手机配置较好的机型才能达到比较好的游戏效果:
问题:磁盘故障预测(Disk Failure Prediction)
(一)背景和说明
在大规模IDCS和云计算环境中,各种磁盘故障是罕见但昂贵的事情。因此,为了节约成本,HDD供应商非常积极的去降低故障率。幸运的是,我们有S.M.A.R.T.(自监控、分析和报告技术),从计算机硬盘驱动器(HDDs)、固态驱动器(SSDs)和eMMC驱动器收集的日志,这些日志报告各种驱动器SMART属性,目的是预测硬件故障。SMART属性表示HDD健康状况统计信息,例如扫描错误的数量,重新分配计数和HDD的试用计数。如果被认为对HDD健康状况至关重要的属性超过一定阈值,则HDD被标记为可能故障。自2013年以来,Backbreze根据他们的数据中心发布了统计数据和相关分析,以及这些报告的数据。关于本问题,您可以从Backblaze网站下载SMART日志,然后需要设计并实现一种基于机器学习的解决方案,来预测每天的磁盘故障(在每个测试日输出预测结果)。解决方案应包括以下几个部分:
·数据预处理和特征工程的方法或流程。
·如何选择机器学习模型并调整参数?
·如何评估结果?
·从这项任务中获得哪些经验教训?
提示:
·您可从这里了解更多的背景信息。
·您可以考虑以周或以月来评估结果。
·需提供代码和结果图表。
(二)相关研究[1]
Pinheiro等人在Google数据中心分析了超过10万个企业级硬盘驱动器中的大型磁盘驱动器的故障趋势。他们发现特定的SMART参数(扫描错误,重新分配计数,离线重新分配计数和试用计数)跟故障有很大关系。最重要的是,大部分故障驱动器在其所有监测的SMART属性中都没有出现故障迹象,因此不太可能实现仅基于SMART信号建立准确的预测故障模型[2]。
BackBlaze分析了其HDD故障和SMART属性之间的相关性,并发现了SMART5,187,188,197和198与HDD故障的相关率最高。这些SMART属性还与扫描错误,重新分配计数和试用计数有关[3]。
El-Shimi等发现在随机森林模型中除了以上5个特征还有这5个SMART属性有最大权重,它们是:SMART9,193,194,241,242[7]。
Pitakrat等人评估了21种用于预测硬盘故障的机器学习算法。 Pitakrat等人发现,在测试的21种ML算法中,随机森林算法在ROC曲线下有最大面积,而KNN分类器具有最高的F1值[4]。
Hughes等人也研究用于预测HDD故障的机器学习方法。他们分析了SVM,朴素贝叶斯的表现。 SVM实现了最高性能,检测率为50.6%,误报率为0%[5]。
(三)数据集
实验使用Backblaze.com上的BackBlaze Dataset。Backblaze是一个在线备份和云存储提供商,可在86529个企业硬盘上开源公共信息。Backblaze提供2013-至今期间HDD的SMART属性和健康状况的每日快照报告。这些硬盘驱动器来自众多硬盘驱动器供应商,包括:希捷,日立,HGST,西部数据,东芝和三星,容量从2TB到8TB[6] 。
如上图所示,2018年第一季度每个csv文件包含255个变量,这些变量代表原始和规范化形式的SMART特征,以及收集数据的日期,HDD的序列号,型号,总容量(以字节为单位)和故障状态(0表示未故障1表示故障)。一旦HDD的故障状态变为1,它就表示故障并随后从所有未来的数据列表中删除并将新硬盘添加到数据中。由于每个供应商都有自己的收集SMART属性的方法,因此并非所有HDD都包含相同的SMART属性集。所以你可以看到有些特征是空的。如果磁盘的SMART属性为空且它是用于预测的属性的话,那么我们对数据点用零进行填充。
为了在各个模型中获得一致的结果,所有模型都用2018年第一季度到2018年第三季度的9个月数据训练。然后,所有模型使用2018年第四季度数据进行测试。
(四)KNN实验
4.1 数据预处理
·过滤指定特征的原始数据而非正则化数据:正则化定义不明(如有必要可自行定义并进行正则化)
·为减小样本点X中0与非0元素的差异,对X进行log(x+1)操作;KNN不需要正则化这会使得样本点抱团
·故障平滑或回溯:对故障HDD选前n天进行回溯,重置failure status为1记为正样本
·选择特定型号HDD:我们选的是“ST4000DM000”型号,因为可用数据量大
·平衡数据集:对于故障硬盘,随机采该盘正常时的n天数据
4.2 特征工程:这里只考虑特征选择
简要的概述一下特征工程:特征工程需要做两件事1.特征构建2.特征选择。当没有特征时我们要去构建去设计特征,当有了可选特征时我们要从特征集合中去选择特征子集来做实验。其中特征选择需要回答一下4个问题:1.如何进行特征选择(即选哪些特征) 2.为什么要选这些特征3.如何获得这些特征。对于第一点如何进行特征选择也即选哪些特征一般的方法是:a)过滤式选择:例如根据已有的研究成果进行挑选 b)包裹式选择:根据实验结果选择特征子集 c)嵌入式选择:自动选择,相比上面的缺点是我不知道它选了啥特征[8]。回答了如何进行特征选择(选哪些特征)也在一定程度上回答了为什么要选这些特征。利用传统机器学习方法的话一定会涉及到特征提取和选择问题,而且特征这里面可以大作文章例如a方法一般用于简单实验比如本文,b方法一般用于工业界,c方法一般用于学术创新;而利用深度学习方法的话它不太刻意去做特征挑选而是重点在如何将原始数据特征化、量化,在较高级的特征空间中特征的提取、选择是在深度网络中自动完成的,这带来的好处是不用过多的人工设计挑选提取特征,缺点是特征是什么未知。
200多个变量和数百万个数据点不仅需要花费大量时间进行训练和测试,而且还会导致过度拟合。为了减少计算工作量并提高模型的性能,我们仅选择最相关的属性特征,并避免使用大量空值的数据点。
由于计算机上的RAM有限,我们将属性个数限制为最多10个SMART属性。首先,根据BackBlaze分析我们选择了这五个与磁盘故障高度相关的特征:SMART 5,187,188,197和198。然后我们根据El-Shimi的实验分析,还有这5个特征也可以考虑它们是:SMART9,193,194,241,242。值得注意的是这10个特征在不同的模型中也不是都全用,比如在Logistic回归中有人使用SMART 193,194,241,197和9,Naive Bayes中有人只用SMART 5,187,188,197和198,Random Forest使用SMART5,187,188,197,198,9,193,194,241和242(10个全用)作为其输入特征。对于KNN,我将选择所有这10个特征。
4.3 模型的选择
这里挑选KNN模型来实验(有必要的话各种模型都尝试一下进行比较)。KNN优点:精度高、对异常值不敏感、对输入没有特定假设要求;缺点:计算复杂度高,空间复杂度高。调参:k取2, 3, 5, 7。
4.4 模型的评估
评估方法:十折交叉验证;评估指标:Precision,Recall,Accuracy,F1,ROC曲线
4.5 实验结果
有必要可以多跑几个模型,进行横纵向比较,找到最优模型。这里log(x+1)处理项中F表示没有对X进行处理,T表示进行了该处理,从结果我们可以发现应当对原始数据进行对数化处理以保证减少输入数据值间的差距。
开源代码
Reference:
[1] 主要参考:Proactive Prediction of Hard Disk Drive Failure
TensorFlow保存和读取模型 加载图结构和参数:
import tensorflow as tf ckpt = tf.train.get_checkpoint_state('./model/') #通过检查点文件锁定最新的模型 saver = tf.train.import_meta_graph(file_path[0]) #载入图结构,存在在.meta文件中 with tf.Session() as sess: saver.restore(sess,file_path[1]) #载入参数,参数保存在两个文件中 参考链接
查看TensorFlow的预训练权重.npy文件 import numpy as np pre_train = np.load("pnet.npy",allow_pickle = True,encoding = 'latin1') print(pre_train) 参考链接
将TensorFlow的.npy模型文件转换为caffe模型 直接附代码:
import sys import tensorflow as tf import caffe import numpy as np import cv2 sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True)) from tensorflow.python import pywrap_tensorflow checkpoint_path = "./pnet.npy" # .npy模型文件的存放地址 pre_train = np.load(checkpoint_path, allow_pickle=True, encoding="latin1") dict = pre_train.
vue/cli2版本 npm install -g vue-cli vue init <template-name> <project-name> vue init webpack firstvue vue/cli4版本 npm install -g @vue/cli vue -V vue create my-project
XML 1.TinyXML库 TinyXML是一个C++的XML解析库 使用介绍:
https://www.cnblogs.com/mythou/archive/2011/11/27/2265169.html 使用的时候,只要把
tinyxml.h、tinystr.h、tinystr.cpp、tinyxml.cpp、tinyxmlerror.cpp、tinyxmlparser.cpp 这六个文件导入工程,然后#include ” tinyxml.h”就可以使用。
2.XML介绍 XML 可扩展标记语言 ,用来传送和携带数据信息(vs html 用来展示数据) XML 文档内容 分成 标记 + 内容
标记: 以<开头,以>结尾。不是标记的东西就是内容。
一个标记结构称为tag标签。形式有如下三种:
start-tag: 如<section>; end-tag: 如</section>; empty-element tag: 如<line-break />. 元素: 在start-tag与匹配的end-tag,例如: <greeting>Hello, world!</greeting>
作为一个empty-element tag,例如: <line-break />
属性: 在start-tag 内部的“名字-值对”,例如:。<person name=haha>
在empty-element tag 内部的“名字-值对”,例如:<img src="madonna.jpg" alt="Madonna" />
每个元素中,一个属性最多出现一次,一个属性只能有一个值
XML 文档的组织结构就是由一棵元素树组成的,整个文档就是一个根元素。
3.DOM document object model 文档对象模型 用来解析结构化文档的(xml, html)
https://blog.csdn.net/qq_15037231/article/details/76396322
https://docs.microsoft.com/zh-cn/dotnet/standard/data/xml/xml-document-object-model-dom
https://developer.mozilla.org/zh-CN/docs/Web/API/Document_Object_Model/Introduction
读取INI配置文件 GetPrivateProfileString 函数用于获取INI配置文件中的内容
读取 ini 文件
在@ServerEndpoint类中的
@OnOpen
public void onOpen(Session session)方法 中 session.setMaxIdleTimeout(3600000);
阿里妹导读:大数据已然是当下的重要课题,大大小小的企业在重视大数据的同时,也渐渐重视大数据质量的问题。阿里巴巴测试开发专家小郅,今天会分享他对数据测试的系统性思考。文章内容架构清晰,内容较长,建议大家收藏阅读哦~
关于数据测试,已有不少同学写过这方面的文章或者开发过工具。为了系统化,我的想法是从数据质量模型入手,分析数据测试的抓手,然后找出数据测试中需要什么样的工具来支撑。这里我也不会过于强调我们做的平台,或与其他平台作比较,而是想把平台或者工具背后的思考过程总结和分享下。
一、数据质量模型的探寻
1.1. ISO 9126在数据质量上的移植
在讲到数据测试前,需要先想一个问题,怎么样系统化地阐述数据质量?
我觉得系统化阐述的一个思路就是寻找当下有没有适合数据质量的质量模型。以传统的质量模型为例,ISO 9126是一种典型的软件质量模型,无论是开发还是测试,无论是各端质量还是服务质量,质量上的大方向不会跳出9126的模型。作为互联网行业,虽然现阶段9126中的二级特性不可能完全落地,但作为一个指导性的质量模型,它会确保质量不会有方向性的大纰漏。那数据质量有没有类似9126的模型可以参考呢?
从国外看,已知的 ISO 8000是现在数据质量方面的新兴标准,但该标准一是太重,二是不免费提供,三是国内对该标准的综述也少的可怜,因此并没有太多细节可供参考。从国内来看,大家都会做到一些总结和落地,包括集团内部的ATA文章也不少,有共性也有不同,但系统性的阐述相对少一些。我的一个想法是,既然没有现成的,那是否可以尝试将9126移植到数据质量?
9126的一级特性可以分为以下几个:功能性、易用性、可靠性、效率、维护性、可移植性。那这几个大项对应到数据质量里,会是什么样的呢?
1)功能性:软件提供了用户所需要的功能。二级特性包括:适合性、准确性、互用性、安全性。对数据而言,个人觉得最重要的应该属于准确性和安全性。
a.对于准确率,如果一句话概括就是,首先数据要有,其次数据要全,最后数据要准。对应的,就可以看到该大项下对应的小项:
数据要有 -> 数据及时性:数据要按约定时间产出。
数据要全 -> 数据完整性:数据不能少、不能缺。当然,也不能多。
数据要准 -> 数据准确性:数值要准确。
这几个二级特性,可能很多同学的文章中都写过,也讨论过。这里只是从数据质量整体系统性上再将其阐述一遍。需要说明的一点是,很多文章中也写到了数据一致性这个特性。数据一致性这个概念很广,比如关系数据库中的外键一致性、CAP 理论中的强弱一致性。个人认为,数据不一致最终影响的还是数据的完整或者准确。如果业务上认为不一致性可以接受,那也不是问题。所以我更倾向于将数据一致性作为一种根因,而并不是质量模型的一个子项。
b.对于安全性,尤其是数据安全,命题也很大,这里不再赘述。但需要提的一点是,数据安全涉及到隐私或者差分攻击的预防,也可能是由业务同学考虑的范畴,所以在数据质量模型中不能忽视。
2)易用性:是指在指定条件下使用时,软件产品被理解、学习、使用和吸引用户的能力。对于数据来说,我认为数据的易用可以分为两方面:是否被理解,是否被需要。它更多的是和日常沟通、产品需求及规划相关。
是否被理解,意思是当前我们对数据的定义是否是行业认可的,是否存在团队与团队之间、用户与开发者之间理解的不一致。
是否被需要,意思是当前我们提供的数据,是否真的能够满足用户需要,数据的真正效果有没有达到。比如,我们给用户提供的是它自己品牌的数据,但用户可能更需要的是行业下的数据来做进一步的市场规划。
3)可靠性:在指定条件下使用时,软件产品维持规定的性能水平的能力。比如上游数据无法定时给出,依赖关系的强弱配置不正确,可能影响的就是数据无法定时产出。可靠性是一种根因,最终影响的还是功能性。
4)效率:是指在规定条件下,相对于所用资源的数量,软件产品是否在规定时间内可提供适当的性能的能力。比如计算倾斜或者计算资源不足导致数据产不出来。效率也是一种根因,最终影响的还是功能性。
5)可维护性:是指是在修改或者新增需求时,当前的开发架构是否足够灵活的支持,是开发阶段主要考虑的。比如在数仓开发中,当新上游到来时,如果从下到上全部采用烟囱式开发,那对新增的需求必定是不友好的。如果改为 Hub 或者集市模式,可能只需要开发接入数据的 ETL 代码,剩下的完全可以复用,就是提升可维护性的一种手段。
6)可移植性:是指软件产品从一种环境迁移到另一种环境的能力,也是开发阶段主要考虑的。服务或者网站的可移植性大家了解比较多,数据的可移植性是指什么?我个人认为可移植性强调的更多是跨技术平台的移植,而不是模块间的数据复用。在数据上可能就是数据直接从一个计算平台迁移到另一个计算平台,或者 SQL 代码从一个计算平台迁移到另一个计算平台。在可移植性方面,我还没有遇到导致质量问题的有说服力的案例,如果大家有相关的例子可以沟通。
综上,如果采用9126的思路,得到的数据质量模型的脑图如下。
1.2. 对移植模型的优化
但是移植过来之后就完事儿了吗?其实细想一下,里面还是有很多的问题,让它不是那么好用。比较典型的问题就是:模型不正交。通俗来讲就是感觉几个特性之间有不同,但也有关系。两个例子:
1)比如无论是可靠性、效率还是可维护性,最终影响的都是功能性,或者可以说是导致功能性问题的部分根因。可以说,功能性是用户最终看到的质量特性,而可靠性、效率、可维护性却是研发看到的质量特性。
2)有些特性又有相同点,又有不同点。比如可靠性和效率,相同点在于,虽然问题产生原因不同,但最终都会导致数据不产出。在不产出的情况下,临时解法可能都会一样,比如切前一天的数据。不同点在于,问题的根本解法有很大的不同,可靠性还是要靠强弱依赖关系检查、架构优化等手段解决,而效率问题要靠资源扩容等手段解决。
怎么样能让模型更好用呢?我在上面的基础上进行了简单的修改。
首先将质量特性分为用户可见的质量特性和研发可见的质量特性。因为导致用户可见的质量特性出现问题的原因,很大程度上取决于研发可见的质量特性。
研发可见的质量特性又分为治标特性和治本特性。所谓治标特性是指兜底,例如,如果数据产出出了问题,那我们有没有快速的兜底恢复方案,是应用降级、限流还是切换旧数据?所谓治本特性是指出问题的根本原因,包括可靠&可维护性、效率、安全。这里把可靠和可维护性合并,是觉得两个联系紧密,都和研发的架构有关。把安全性从功能性移到这里,是觉得安全性对于用户来说可见性没有那么强,但一旦可见,后果非常严重,是需要在研发阶段重点考虑的。通过可见性范围将质量模型进行重构后,在模型正交上会显得比之前相对好些。
二、数据测试方法论探寻
2.1.数据质量模型应用于研发过程
既然数据质量模型有了雏形,接下来需要思考的就是质量模型在研发过程中的落地,也就是由谁在什么时间做什么事情?首先,我们先把质量模型平铺到研发周期中去,x 轴为研发周期,y 轴为质量模型,接下来要做的就是填空题,即每个研发阶段在某个质量特性上该做什么事情,这样就得到了一个二维关系,如下图所示。里面的内容其实是我们根据自己产品线特性以及质量活动经验总结出来的,但总体看下来,大致和传统质量是相似的。
填完内容之后,至于由谁来做就一目了然了。易用性的问题涉及到商业调研、用户需求和产品规划,更多的是 PD 主导的事情。其他几个特性,也就是蓝框中的特性都是开发测试阶段需要考虑的特性。
2.2.数据质量模型中的测试抓手
那测试的抓手主要在哪儿?很明显,如果从代表用户的角度,那最直接的切入点就是功能性这个特性。一方面它是用户可见的特性,测试从用户的角度发现问题;另一方面所有研发可见的特性导致的质量问题最终都会落到功能性上,可以用功能性做问题发现的最后兜底。
除了功能性,还有需要测试重点考虑的特性么?我个人的经验是,容灾性是需要考虑的。因为作为研发修复问题的兜底方法,容灾性的有无或好坏会严重影响到功能性。这也是我把他从质量模型中独立出来的一个考虑。测试在容灾的预案制定上应该起到一定的 review 作用。
至于其他几个特性,效率也好,可靠&可维护性,安全性也好,要根据项目性质是日常还是大促,是功能新增还是功能优化,甚至测试团队是新建还是有所积累有关。对于日常项目、功能新增、团队新建等,在功能性&容灾上的投入是最大的,而功能性测试又是两者中最大的。随着功能性上的完善,会逐渐投入到效率、可靠&可维护性上。而在大促、功能优化、团队积累时,在容灾性、效率、可靠性&可维护性上的投入比功能性要更重。所以我认为数据测试公式应该是:
数据测试 = 基础测试(功能性 + 容灾性) + 选择评估(效率 ||可靠&可维护性 || 安全性)
第一章 sersync/lsync实时同步 1.1 实时同步服务原理/概念 1)需要部署好rsync守护进程服务,实现数据传输
2)需要部署好inotify服务,实现目录中数据变化监控
3)将rsync服务和inotify服务建立联系,将变化的数据进行实时备份传输
1.2 inotify介绍 ݦ Inotify是一种强大的,细粒度的,异步的文件系统事件监视机制,Linux2.6.13起加入了inotify支持,通过inotify可以监控文件系统中添加,删除,修改,移动等各种事件,利用这个内核接口,第三方软件就可以监控文件系统下文件的各种变化情况,而inotify-tools正是实施这样监控的软件,另外一个这样效果的软件是中国人周洋在金山公司开发的sersync,还有一个配置更简单的软件叫lsyncd
1.2.1 查看当前系统是否支持inotify [root@nfs data]# uname -r 3.10.0-693.el7.x86_64 1.2.2 安装inotify-tools [root@nfs data]# yum -y install inotify-tools 1.2.3 关键参数说明 [root@nfs backup]# ll /proc/sys/fs/inotify/ total 0 -rw-r--r-- 1 root root 0 Jul 19 15:46 max_queued_events -rw-r--r-- 1 root root 0 Jul 19 15:46 max_user_instances -rw-r--r-- 1 root root 0 Jul 19 15:46 max_user_watches ----------------------------------------------------------------------------- max_queued_events #设置inotify实例事件(event)队列可容纳的事件数量 max_user_instances #设置每个用户可以运行的inotify或者inotifywatch命令的进程数 max_user_watches #设置inotifywait或者inotifywatch命令可以监控的文件数量(单进程) 1.2.4 inotifywait命令参数说明 inotifywait命令参数说明 参数名称 参数说明 -m ,-monitor 始终保持事件监听状态 -r,-recursive 递归查询目录 -q,-quiet 只打印监控事件的信息 -exclude 排除文件或目录时,不区分大小写 -t,-timeout 超时时间 -timefmt 指定时间输出格式 -format 指定时间输出格式 -e,event 后面指定增,删,改等事件 inotifywait events 事件说明 access 读取文件或目录内容 modify 修改文件或目录内容 attrib 文件或目录的属性改变 close_write 修改真实文件内容 open 文件或目录被打开 moved_to 文件或目录移动到 moved_from 文件或目录从.
本人5月份往Journal of Process Control期刊投了一篇论文,是基于深度学习图像序列预测的。前几天收到一审结果,大修。两个审稿人给了几篇参考文献,此贴专门用来做笔记方便自己查阅。
论文1: Video salient object detection via fully convolutional networks
提出了一种深度学习模型,可以有效地检测视频中的显着区域。解决了两个重要问题:
1)深度视频显着性模型训练,缺少足够大和按像素标注的视频数据;
2)快速视频显着性训练和检测。
所提出的深度视频显着性网络包括两个模块,分别用于捕获空间和时间显着性信息。动态显着性模型结合静态显着性模型的显着性估计,直接产生时空显着性推断而无需耗时的光流计算。并提出了一种新颖的数据增强技术。利用大量图像训练数据来合成视频数据的新技术。CNN模型可以在丰富的视频和图像上进行有效且完整的训练,从而成功地学习静态和动态显着特征。 显着性模型由两个模块组成,这两个模块设计用于同时捕获空间和时间显着性信息。静态显着性网络将单帧作为输入并输出静态显着性估计。动态显着性网络从帧对中学习动态显着性,并将第一个模块生成的静态显着性作为先验,从而产生最终的时空显着图。
静态显着性检测网络的插图。网络采用单帧图像(例如,224 × 224 )作为输入,采用多层卷积网络,将输入图像转换为多维特征表示,然后应用一堆反卷积网络对从卷积网络中提取的特征进行上采样。最后,一个完全卷积网络1 × 1 内核和sigmoid活动函数用于输出与输入相同大小的概率图,其中较大的值表示较高的显着性值。
网络动态显着性检测的插图。连续帧对来自真实视频数据或从现有图像数据集合成,以及从我们的静态显着性网络推断出的静态显着性信息被连接并馈送到动态网络中,该动态网络具有与静态网络类似的FCN架构。动态网络捕获动态显着性,同时考虑静态显着性,从而直接生成时空显着性估计。
总结:
1、论文一直强调将单个视频帧输入到神经网络训练,往往没有学习时间信息,但在我的网络中,LSTM部分似乎可以解释学习到了时间信息。
2、论文中的数据集是将大量图像数据合成视频数据,而我本来就是用视频根据时间顺序按帧提取的,同样包含时间信息。
论文2: A deep network solution for attention and aesthetics aware photo cropping
研究照片裁剪的问题,其目的在于找到输入图像的裁剪窗口,以尽可能地保留其重要部分,同时在美学上令人愉悦。(感觉与我论文的内容不太相关,没有深入研究)
论文3: Stochastic Configuration Networks: Fundamentals and Algorithms
提出的学习者模型由随机配置(SC)算法(称为SC网络(SCN))递增地生成。与现有的单层前馈网络随机学习算法相比,根据监督机制随机分配隐藏节点的输入权重和偏差,并以建设性或选择性方式对输出权重进行分析评估。
主要和原始贡献在于为随机参数分配不等式约束并自适应地选择随机参数的范围,确保构建随机化的通用逼近性质。SCN的三种算法实现,即算法SC-I,SC-II和SC-III,具有用于配置随机参数的相同监督机制,但是计算输出权重的方法不同。具体地说,SC-I采用一种建设性方案来仅为新添加的隐藏节点评估输出权重,并保持所有先前获得的输出权重不变; SC-II通过用户指定的移位窗口大小求解局部最小二乘问题来重新计算当前输出权重的一部分; 和SC-III通过解决当前学习者模型的全局最小二乘问题,一起找到输出权重。
神经网络的过程不是用固定的架构训练学习者模型,而是从小型网络开始,然后逐步添加隐藏节点,直到达到可接受的容差。该方法不需要关于给定任务的网络复杂性的任何先验知识。
总结:与用于单层前馈神经网络(例如,随机向量功能链路网络)的已知随机学习算法相比,随机配置网络(SCN)根据监督机制随机分配隐藏节点的输入权重和偏差。 同时以建设性或选择性方式对输出权重进行分析评估。(随机学习算法,在线性回归和图像分类任务中表现优)
KNN算法是分类算法中最简单的一个算法了,关于这个算法的原理我就不做详细介绍了,这么简单的算法,究竟能不能用来准确的进行分类呢?其正确率又有多高呢?
带着一点怀疑,咱来进行这个实验,我们就用最简单的KNN算法来进行手写数字识别,编程语言是python 3。
首先讲一下思路,常规的机器学习算法大致有如下几个步骤:
1、收集数据
2、数据预处理
3、寻找一个function set
4、通过对数据进行训练以找到最好的function
5、用与训练集的数据不同的测试集对这个function进行测试
6、将训练好的模型进行实际应用
但是KNN算法省去了这其中很多步骤,是不需要训练数据的,同样的也不存在找最佳的function了,因此本实验的步骤就是:
1、收集数据
2、数据预处理
3、拿测试集进行测试,并记录其正确率
4、将这个模型进行实际应用
首先导入一些需要用到的库
from numpy import * from os import listdir import operator from PIL import Image 然后定义一个名为classify0的函数,该函数计算了测试数据距离数据集中每一组数据的距离,并对该距离进行排序,并运用了KNN算法返回预测结果。别看说得这么抽象,其实很简单,代码也不多,下面我会详细解释。
inX为输入的测试数据,其格式为一个1行n列的list(n为特征个数),而dataSet就算训练数据集,每一组数据占据1行,因此其为一个m×n的list(m为训练数据的数量),labels是一个m行1列的list,它对应着dataSet中每一行的标签,即预测的结果,k就算KNN算法中的那个k了。
def classify0(inX, dataSet, labels, k): # 获取测试数据的行数 dataSetSize = dataSet.shape[0] # 请注意tile函数的作用,它将inX列表进行了复制,复制成了跟dataSetSize的行数一样的一个矩阵(不理解的请先去百度一下),然后将进行复制后的矩阵每一个值都减去dataSet,这是要为计算距离做准备了 diffMat = tile(inX, (dataSetSize, 1)) - dataSet # 差值平方 sqDiffMat = diffMat**2 # 计算距离,axis=1表示将每一行的值加起来,因此结果是m行1列 sqDistances = sqDiffMat.sum(axis = 1) # 真正的距离,这里是开根号 distances = sqDistances ** 0.
i++ 与 ++i 的主要区别有两个:
1、 i++ 返回原来的值,++i 返回加1后的值。
2、 i++ 不能作为左值,而++i 可以。
// 前缀形式: int& int::operator++() //这里返回的是一个引用形式,就是说函数返回值也可以作为一个左值使用 {//函数本身无参,意味着是在自身空间内增加1的 *this += 1; // 增加 return *this; // 取回值 } //后缀形式: const int int::operator++(int) //函数返回值是一个非左值型的,与前缀形式的差别所在。 {//函数带参,说明有另外的空间开辟 int oldValue = *this; // 取回值 ++(*this); // 增加 return oldValue; // 返回被取回的值 } 左值是对应内存中有确定存储地址的对象的表达式的值,而右值是所有不是左值的表达式的值。 一般来说,左值是可以放到赋值符号左边的变量。但能否被赋值不是区分左值与右值的依据。比如,C++的const左值是不可赋值的;而作为临时对象的右值可能允许被赋值。 左值与右值的根本区别在于是否允许取地址&运算符获得对应的内存地址。 比如: int i = 0; int *p1 = &(++i);//正确 int *p2 = &(i++);//错误 ++i = 1;//正确 i++ = 1;//错误 转载于:https://www.
dpkg是Debian的包管理器,因为Ubuntu是Debian的变体,在Ubuntu下也有这个工具。
两个常用的命令是:
dpkg -i package-file和dpkg -r package
分别表示安装和移除软件包。当然使用:dpkg -P package还可以做到移除软件包时,清除掉配置文件。
要查询已安装的软件包的状态,可以使用:dpkg-query -s packagecpu-name
下面谈一下我遇到的一个问题。我在arm64机器上安装amd64类型的包,弹出的错误为:
package architecture (amd64) does not match system (arm64)
装不上,有人给出解决办法:sudo dpkg --add-architecture amd64
这样做以后就能装上了。个人认为,如果这样做能解决问题,当然很好;如果不能,还得寻找其他的解决途径。
这里说一下architecture的问题,一个编译好的软件是与操作系统类型,cpu架构都有关的。这个architecture就是cpu的体系结构。
命令一:
sudo dpkg --print-architecture
该命令用于显示本机的architecture,我在不同的机器上得到的结果有:arm64或amd64
命令二:
sudo dpkg --add-architecture architecture
这就是前面提到的那个问题的解决办法。
命令三:
sudo dpkg --print-foreign-architectures
比如你用命令二,增加了一个新的architecture,用这条命令就能打印出来。
命令四:
sudo dpkg --remove-architecture architecture
这和命令二相反,把之前增加的architecture去除。
问题描述:
No plugin found for prefix 'tomcat7' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories [local (C:\Users\yc\.m2\repository), central (https://repo.maven.apache.org/maven2)] -> [Help 1]
解决办法:
自己的本地仓库原来配置的时候如下:
把红色的配置了但是黑色的始终没有变化,对应的c盘下面的默认的本地仓库的位置,就没有管,直到编译的时候报出了上面的错误。最后才发现是
里面当时把位置是改成了自己的,但是没有去掉注释,诶
感觉自己好沙雕,去掉之后就正常了。
前提是要在pom.xml文件中配置下面的
主要原因还是没有找到仓库的位置,所以在setting.xml文件中那块找问题就对了,看自己是否有正确的配置即可。
看过信息系统项目管理师教材和真题的考友们都知道,考试涉及的内容非常烦杂,涵盖面很广泛,几乎涵盖了计算机和项目管理的大部分内容,除此之外,它还有一部分自身特有的内容,如管理运筹学等,书的内容就有九百多页。那么给大家的福利来了,这里为大家整理了一些记忆小口诀,幸福哥预祝大家接下来考试顺利!
一、九大管理:范进整狗子成人风采
范围管理 —— 范
进度管理 —— 进
整体管理 —— 整
沟通管理 —— 狗
质量管理 —— 子
成本管理 —— 成
人力管理 —— 人
风险管理 —— 风
采购管理 —— 采
二、IOS七层结构:巫术忘传会飙鹰
物理层(巫) 会话层(会)
数据链路层(术) 表示层(飙)
网络层(忘) 应用层(鹰)
传输层(传)
三、软件维护的四个特性:就是鱼丸
纠正性(就) 预防性(鱼)
适应性(是) 完善性(丸)
四、信息系统生命周期:花开云消(散)
信息系统规划阶段(花) 信息系统运行与维护阶段(云)
信息系统开发阶段(开) 信息系统更新阶段(消亡阶段) (消)
五、信息系统开发阶段的五个阶段:划分即实验 总体规划阶段(划) 系统实施阶段(实)
系统分析阶段(分) 系统验收阶段(验)
系统设计阶段(即)
六、UML系统静态结构的静态模型:部队包袱够累
部署(部) 复合图(袱)
对象图(队) 构件图(够)
包图(包) 类图(累)
七、UML系统动态结构的动态模型:用东西装信是管制 用例图(用) 通信图(信)
活动图(东) 定时图(是)
顺序图(西) 交互概观图(管)
状态图(装) 制品图(制)
问题截图 刚刚安装的android studio安装完成就出现异常错误
原因 新建project的时候,language项选错了,应选java
解决错误的办法 新建一个Project的时候,Language项选择Java,然后在类里写上private Button的时候会有提示导包
问题到这里就解决完成了,谢谢观看
string转const char *: 1. 使用string的成员函数c_str(); 2. 使用string的成员函数data(); 3. 注意事项:c_str()和data()的不同之处在于,data()会返回没有结束符的字符数组指针。并且需要强调一点,调用c_str()和data()得到的指针指向的地址和原来的string是一个地址,所以只要string改变了,c_str()和data()的返回值也会改变。 测试代码如下:
#include <iostream>
using namespace std;
#include <string>
int main()
{
string s = "123123";
const char *p1 = s.c_str();
cout << "改变string之前的p1的值: ";
cout << p1 << endl;
s = "321321";
cout << "改变string之后的p1的值: ";
cout << p1 << endl;
const char *p2 = s.data();
cout << "改变string之前的p2的值: ";
cout << p2 << endl;
s = "123123";
cout << "
半角全角字符转换函数 public string ToSBC(string input)
{
//半角转全角:
char[] c=input.ToCharArray();
for (int i = 0; i < c.Length; i++)
{ if (c[i]==32) {
c[i]=(char)12288;
continue;
}
if (c[i]<127)
c[i]=(char) (c[i]+65248);
}
return new string(c);
}
/// 转半角的函数(DBC case)
/// 任意字符串
/// 半角字符串
///全角空格为12288,半角空格为32
///其他字符半角(33-126)与全角(65281-65374)的对应关系是:均相差65248
public string ToDBC(string input)
{
char[] c=input.ToCharArray();
for (int i = 0; i < c.Length; i++)
{
if (c[i]==12288) {
c[i]= (char)32; continue;
}
if (c[i]>65280 && c[i]<65375)
转载自:https://jingyan.baidu.com/article/4ae03de32e9c9d3eff9e6b3a.html
1**:请求收到,继续处理
2**:操作成功收到,分析、接受
3**:完成此请求必须进一步处理
4**:请求包含一个错误语法或不能完成
5**:服务器执行一个完全有效请求失败
状态代码 状态信息 含义 100 Continue 初始的请求已经接受,客户应当继续发送请求的其余部分。(HTTP 1.1新) 101 Switching Protocols 服务器将遵从客户的请求转换到另外一种协议(HTTP 1.1新) 200 OK 一切正常,对GET和POST请求的应答文档跟在后面。
201 Created 服务器已经创建了文档,Location头给出了它的URL。 202 Accepted 已经接受请求,但处理尚未完成。 203 Non-Authoritative Information 文档已经正常地返回,但一些应答头可能不正确,因为使用的是文档的拷贝(HTTP 1.1新)。 204 No Content 没有新文档,浏览器应该继续显示原来的文档。如果用户定期地刷新页面,而Servlet可以确定用户文档足够新,这个状态代码是很有用的。 205 Reset Content 没有新的内容,但浏览器应该重置它所显示的内容。用来强制浏览器清除表单输入内容(HTTP 1.1新)。 206 Partial Content 客户发送了一个带有Range头的GET请求,服务器完成了它(HTTP 1.1新)。 300 Multiple Choices 客户请求的文档可以在多个位置找到,这些位置已经在返回的文档内列出。如果服务器要提出优先选择,则应该在Location应答头指明。 301 Moved Permanently 客户请求的文档在其他地方,新的URL在Location头中给出,浏览器应该自动地访问新的URL。 302 Found 类似于301,但新的URL应该被视为临时性的替代,而不是永久性的。注意,在HTTP1.0中对应的状态信息是“Moved Temporatily”。
出现该状态代码时,浏览器能够自动访问新的URL,因此它是一个很有用的状态代码。
注意这个状态代码有时候可以和301替换使用。例如,如果浏览器错误地请求http://host/~user(缺少了后面的斜杠),有的服务器返回301,有的则返回302。
严格地说,我们只能假定只有当原来的请求是GET时浏览器才会自动重定向。请参见307。
303 See Other 类似于301/302,不同之处在于,如果原来的请求是POST,Location头指定的重定向目标文档应该通过GET提取(HTTP 1.1新)。 304 Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。 305 Use Proxy 客户请求的文档应该通过Location头所指明的代理服务器提取(HTTP 1.
使用security框架后如何修改用户密码 BCryptPasswordEncoder bc = new BCryptPasswordEncoder(); //修改密码要求输入原密码password(未加密),paaword2为数据库取出的该用户加密后的密码,对两者进行对比 //这个核心代码 boolean matches = bc.matches(password,password2 ); @RequestMapping("/updatePassword") public String updatePassword(HttpServletRequest request) { //获取session HttpSession session = request.getSession(); //获取session域的用户名 SecurityContext context = SecurityContextHolder.getContext(); Authentication authentication = context.getAuthentication(); User user = (User) authentication.getPrincipal(); System.out.println(user); String username = user.getUsername(); //获取用户输入的原密码 String password = request.getParameter("password"); //用户输入的新密码 String newPassword = request.getParameter("newPassword"); //根据名字获得用户 SysUser sysUser = sysUserService.findByName(username); //获得用户加密后的原密码 String password2 = sysUser.getPassword(); //判断输入的原密码和加密后的密码是否一致 BCryptPasswordEncoder bc = new BCryptPasswordEncoder(); boolean matches = bc.
今天重新部署了一个3个节点的hadoop完全分布式集群,在第一台节点上安装好hadoop后,使用了伪分布式模式对集群进行了上传文件操作,运行了wordcount案例。在进行完全分布式时,发现有个节点无法启动,查看该节点的 .log文件,发现在文件最后抛出了以下错误。仔细回顾操作过程后,这一系列操作是属于往集群中添加节点。于是,我关闭了集群,并在namenode节点的etc/hadoop目录下添加了dfs.hosts文件(暂时没有在hdfs-site.xml中添加dfs.hosts属性),将新节点的名字添加了进去,重启集群发现所有的datanode可以正常启动。
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.hdfs.protocol.UnregisteredNodeException): Data node DatanodeRegistration(192.168.10.106:50010, datanodeUuid=1ed09498-904c-43fd-99c5-5d1611b15c89, infoPort=50075, infoSecurePort=0, ipcPort=50020, storageInfo=lv=-56;cid=CID-a27afbc7-b086-4f78-9e39-7afdd34ed8cc;nsid=2127549857;c=0) is attempting to report storage ID 1ed09498-904c-43fd-99c5-5d1611b15c89. Node 192.168.10.107:50010 is expected to serve this storage. at org.apache.hadoop.hdfs.server.blockmanagement.DatanodeManager.getDatanode(DatanodeManager.java:495) at org.apache.hadoop.hdfs.server.blockmanagement.BlockManager.processReport(BlockManager.java:1788) at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.blockReport(NameNodeRpcServer.java:1321) at org.apache.hadoop.hdfs.protocolPB.DatanodeProtocolServerSideTranslatorPB.blockReport(DatanodeProtocolServerSideTranslatorPB.java:171) at org.apache.hadoop.hdfs.protocol.proto.DatanodeProtocolProtos$DatanodeProtocolService$2.callBlockingMethod(DatanodeProtocolProtos.java:28756) at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:616) at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:969) at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2049) at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2045) at java.security.AccessController.doPrivileged(Native Method) at javax.security.auth.Subject.doAs(Subject.java:422) at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1657) at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2043) at org.apache.hadoop.ipc.Client.call(Client.java:1475) at org.apache.hadoop.ipc.Client.call(Client.java:1412) at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:229) at com.sun.proxy.$Proxy14.blockReport(Unknown Source) at org.apache.hadoop.hdfs.protocolPB.DatanodeProtocolClientSideTranslatorPB.blockReport(DatanodeProtocolClientSideTranslatorPB.java:203) at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.blockReport(BPServiceActor.java:463) at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.offerService(BPServiceActor.java:688) at org.
ssm-security对用户密码加密(数据库加密) 再spring-security配置文件中装配BCryptPasswordEncoder <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/> 再用户注册后,对用户密码用passwordEncoder.encode(password);进行加密再存入数据库 @Autowired PasswordEncoder passwordEncoder; @Override public void save(SysUser sysUser) { String password = sysUser.getPassword(); String encoderPassword = passwordEncoder.encode(password); sysUser.setPassword(encoderPassword); userDao.save(sysUser); } 在重写的loadUserByUsername(username)方法中,设置使用加密登录 @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //根据用户名获取用户对象 SysUser sysUser = userDao.findByUsername(username); if (sysUser != null) { //创建角色集合对象 Collection<GrantedAuthority> authorities = new ArrayList<>(); //创建临时角色对象 GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_USER"); //对象添加到集合中 authorities.add(grantedAuthority); //参数"{noop}"+ sysUser.getPassword() 表示不使用加密登录 //参数sysUser.getPassword() 表示使用密码登录 User user = new User(sysUser.getUsername(), sysUser.
今天前端项目突然遇到这种报错,原来也没有这种问题。突然出现,找了好久的原因。原来是我安装的谷歌插件的问题。
给大家提个醒,不经常使用的插件,一定要修改下配置,因为默认 是可读取和更改网站数据-> 在所有网站上,改成 当你点击此扩展程序时
replace-method 定义bean // 定义原有实体和方法 public class RunMan { public void say(){ System.out.println("i am rum man"); } } // 定义替代方法 public class RunReplacer implements MethodReplacer { @Override public Object reimplement(Object o, Method method, Object[] objects) throws Throwable { System.out.println(o.getClass().getName()); System.out.println(method.getName()); System.out.println("i am replacer"); return null; } } 定义xml <bean id="runMan" class="org.dhcao.relax.spring.replace.RunMan"> <replaced-method name="say" replacer="replacer"> </replaced-method> </bean> <bean id="replacer" class="org.dhcao.relax.spring.replace.RunReplacer"></bean> 测试代码 public class Main { public static ApplicationContext context = null; public static void main(String[] args) { context = new ClassPathXmlApplicationContext("
作者 | 素年清时
责编 | 伍杏玲
出品 | 程序人生(ID:coder_life)
5 岁写出第一套电脑程序;14 岁凭借自制的测绘机器人入围英特尔国际科学与工程大奖赛决赛;高中时期发明一套初级的脑电波控制系统,再度入围英特尔大赛;17岁破解第一代苹果手机;27岁研发出汽车自动驾驶系统,秒杀谷歌与特斯拉……
这样开挂的人生对于普通人来说简直不敢想象,可对于乔治·霍兹(George Hotz)来说只是家常便饭,就因为他是“神奇小子”、“天才少年”,是“传奇黑客”。
手机换跑车
2007 年,苹果公司推出第一代 iPhone,这是一款集拍照、PDA、媒体播放器和无线通讯设备于一体的高性能智能手机。由于苹果同 AT&T 公司签署了独家经销协议,iPhone1 只能在 AT&T 网络中使用。
苹果的这种销售模式引发了许多人的不满,一些技术狂人和顶尖黑客纷纷开始了他们对 iPhone 的破解之路。然后,令所有人没想到的是,第一个成功破解iPhone 的人竟是一个 17 岁的少年,乔治·霍兹。
霍兹破解 iPhone1 的方式简单而粗暴:用螺丝刀和吉他拨片撬开手机找到基带处理器,然后在这个小薄片上焊上一条附有电压的线,扰乱它的编码,并写入自己的程序,使其能够在任何运营网络下使用。就这样,初代 iPhone 问世不久就“被迫”变成了“全网通”。
霍兹将自己解码后的手机放在 eBay 上拍卖,不过因为有人捣乱,拍卖价最后竟被炒到了一亿美元以上,最终他没能在 eBay 上卖出这款手机。
毕竟是第一台全球限量版公开破解成功的 iPhone,它的存在注定不同凡响,最后它以一辆 Nissan 350 Z 跑车(07北美款售价在55-58万RMB之间)和三台未破解的 iPhone 手机为代价被一家科技公司的创始人收走。
两年后,也就是 2009 年,在苹果推出第三代 iPhone 之后没多久,霍兹就开发出了 iPhone 3GS 越狱软件。通过这款名为"purplera1n"(即“紫雨”)的公开软件,霍兹把破解 iPhone 这件事从“独乐乐”变成了“众乐乐”。
同年 10 月,霍兹发布全球第一款 iOS3.1 越狱软件 Blackra1n,“紫雨”变“黑雨”, 霍兹也因此和“iPhone”、“ 越狱”这两个词绑在了一起。说起霍兹,人们想起的总是他的越狱软件。
与索尼的官司纠纷
通过破解 iOS 而声名大噪并非天才少年霍兹的本意,他在 2010 年 7 月发布博客称自己最初破解 iPhone 的目的只是出于某种乐趣,但最后事态的发展却出乎了他的意料之外,所以在破解 iPhone4 后,他突然宣布关闭与 iPhone 越狱有关的博客,不再继续开发越狱软件。
spss基本分析和检验总结 因子分析 因子分析:用较少相互独立的因子变量来替代原有变量的大部分信息
因子分析 能减少分析工作量 根据原始变量信息重构反映变量大部分信息 因子变量之间不存在线性相关性 具有命名解释权 因子分析步骤 变量是否适合因子分析构造因子变量旋转因子变量使其更具可解释性计算因子变量得分 因子分析的检验方法 巴特利特球形检验反映像相关矩阵检验KMO检验 主成分分析步骤 数据标准化计算协方差矩阵R求R的前m个特征值以及对应的特征向量,将其标准正交求m个因子的载荷矩阵 spss结果
文章目录 序言源码解读从入口开始initDataobserve函数Observerwalk函数defineReactive 依赖收集Watcher 依赖更新 序言 Vue是当前最流行的框架之一,现在很多项目都或多或少都会用到Vue。所以了解Vue的响应式原理对我们意义非凡,有利于…
我们直接开始吧
源码解读 从入口开始 Vue对数据进行响应式的处理的入口在src/core/instance/state.js文件下的initState函数
export function initState (vm: Component) { vm._watchers = [] const opts = vm.$options if (opts.props) initProps(vm, opts.props) if (opts.methods) initMethods(vm, opts.methods) if (opts.data) { initData(vm) } else { observe(vm._data = {}, true /* asRootData */) } if (opts.computed) initComputed(vm, opts.computed) if (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch) } } 函数参数vm指的是Vue实例,我们可以把它看作是我们平常写vue代码是经常使用的this。
函数首先给vm实例定义_watchers属性,这个什么作用我们暂时不用管,接着往下。
然后获取vm的 o p t i o n s 配 置 。 这 里 的 options配置。这里的 options配置。这里的options配置包括我们Vue预先定义的配置、mixins传入的配置,和我们自己实例话Vue时传入的配置。
输入两个字符串,从第一个字符串中删除第二个字符串中的所有字符
比如输入“They are students."
删除之后的第一个字符串变成"The r stdnts."
思路是利用每个字符都有其对应的ASCII码值,将需要删除的字符的ascii为下标储存在数组当中。
利用两个指针分别指向原字符串和需要删除的字符串。
因为我们已经将需要删除的字符串中的字符所对应的ASCII码作为下标储存在数组当中,所以在比较的时候只需要看原字符串中的字符所对应的ASCII码作为下标在数组中是否为1.
这样说可能不好理解。看一下具体例子
假如原字符串为
char str1[] = "They aaaare students."; 需要删除的为
char str2[] = "aeiou"; 然后我们需要一个数组储存结果(将其初始化为0)
int a[256] = { 0 }; 两个指针分别指向这两个字符串
char* pFast = str1; char* pSlow = str2; 我们想实现的是在字符串str1中找到‘a’,‘e’,‘i’,‘o’,‘u’这几个字符并删除
第一步我们想在str1中找到所有的字符‘a’并删除
也就是说我们所有想删除的字符都在str2中
接下来我们把需要删除的字符对应的ASCII码作为下标,然后储存在数组中
利用一个for循环
for (i = 0; i < n; ++i){ a[str2[i]] = 1; } str2[i]对应的是所有需要在str1中删除的字符
将其对应的ASCII码作为下标也就是 a[str2[i]];
将其赋为1,表示该字符需要删除
接下来实现代码的核心部分
while (*pFast){ if (a[*pFast] == 1){ *pFast++; } *pSlow++ = *pFast++; } 因为我们需要删除的是str1中的字符,所以这里的 while(pFast)是为了遍历str1
从事C++编程已经三年有余,至今仍有一些基础性的知识不是很清楚。工作学习之余,做一下总结。
问题提出:
工作中经常遇到 int paramname_offset = strlen( param_name.c_str() ) + 1;
CopyMemory((char*)pBuf, param_name.c_str(), paramname_offset);
为甚么在 strlen 后面要加1 呢? 下面来验证一下:
char a1[10] = "my";
char a2[] = "my";
const char* a3 = "ab";
std::string a4 = "my";
const char* a5 = a4.c_str();
std::string a6 = a2;
std::string a7 = a1;
std::string a8 = a3;
char a9[3] = "my";
char* a10 = "my";
结果:
总结:
1. const char* 字符串 以 “\0”结尾。
Feign传参注意
最近在用SpringCloud尝试重构以前的项目,使用Feign客户端组件来调用微服务,经常出现参数传不过去变成null的问题,网上查了一下发现feign在参数上的使用还是有一定的限制的,主要是要注意:
当参数比较复杂时,feign即使声明为get请求也会强行使用post请求
不支持@GetMapping类似注解声明请求,需使用@RequestMapping(value = "url",method = RequestMethod.GET)
使用@RequestParam注解时必须要在后面加上参数名
写了一个简单案例,同时传输一个对象和一个字符串作为请求参数,
消费端controller package com.taotao.feignchuanzhi.controller; import com.sun.org.apache.xerces.internal.xs.datatypes.ObjectList; import com.taotao.feignchuanzhi.entity.User; import com.taotao.feignchuanzhi.service.FeignService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; @RestController public class FeignController { @Autowired private FeignService feignService; //String 类型传值通过feign传递 @RequestMapping("/getOrderName") public String getOrderName(String name){ return feignService.getName(name); } /** * feign 多个参数传值 * @param name * @param pass * @return */ @RequestMapping("/getOrderNameMore") public String getOrderNameMore(String name,String pass){ return feignService.
依赖的npm包:
exceljs 导出数据到excel表中node-fetch 在nodejs端发送http请求 封装一个工具函数
/** * 插入图片到excel * @param {object} wb 工作簿 * @param {object} ws 工作表 * @param {array} data 数据 * @param {number} col excel表图片列的索引 * @param {object} ext 额外描述 * @param {string} fieldName 数据中图片的键名 */ async function insertImg2excel({ wb, ws, data, col, ext, fieldName }) { const promises = data.map(async (d, i) => { const url = d[ fieldName ] if (!url) { return } const ret = await fetch(url) const bufferData = await ret.
Security登录成功后session域获取用户信息 标签获取用户名 <%@ taglib prefix="security" uri="http://www.springframework.org/security/tags" %> <security:authentication property="principal.username"/> 使用标签需要导约束 表达式获取 ${sessionScope.SPRING_SECURITY_CONTEXT.authentication.principal.username} java代码获取 @RequestMapping("/showUsername") public void showUsername(HttpServletRequest request) { //获得session对象 HttpSession session = request.getSession(); //取出session域中所有属性名 Enumeration attributeNames = session.getAttributeNames(); while (attributeNames.hasMoreElements()) { System.out.println(attributeNames.nextElement()); } //SPRING_SECURITY_CONTEXT Object spring_security_context = session.getAttribute("SPRING_SECURITY_CONTEXT"); System.out.println(spring_security_context); SecurityContext securityContext = (SecurityContext) spring_security_context; //获得认证信息 Authentication authentication = securityContext.getAuthentication(); //获得用户详情 Object principal = authentication.getPrincipal(); User user = (User) principal; String username = user.getUsername(); System.out.println(username); //第二种方法 //获取上下栈 SecurityContext context = SecurityContextHolder.
移动平滑异同平均线(Moving Average Convergence Divergence,简称MACD指标)策略,被称为“指标之王”,经常使用它,当日要常备在数据库了。 macd计算方法,不求多完美,能对标常用的炒股软件就好了。需要的结果又macd值(红绿柱),diff(快线),dea(慢线)
主要用到talib库talib.MACD方法。
代码实现:
diff, dea, my_macd = talib.MACD(close_all, fastperiod=12, slowperiod=26, signalperiod=9) 其中,closeall是某只股票的一组收盘数据。
下图与 炒股软件对标,基本一致,夫复何求?
文章目录 方案1:修改注册表方案2:更换密钥(推荐)密钥 方案1:修改注册表 将以下内容复制保存,文件名重命名为.reg,双击运行
Windows Registry Editor Version 5.00 [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion] "ProductId"="69713-640-9722366-45198" [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion] "CurrentBuild"="1.511.1 () (Obsolete data - do not use)" "InstallDate"=dword:3f6c976d "ProductName"="Microsoft Windows Server 2003" "RegDone"="" "SoftwareType"="SYSTEM" "CurrentVersion"="5.2" "CurrentBuildNumber"="3790" "BuildLab"="3790.srv03_rtm.030324-2048" "CurrentType"="Uniprocessor Free" "ProductId"="69713-640-9722366-45198" "DigitalProductId"=hex:a4,00,00,00,03,00,00,00,36,39,37,31,33,2d,36,34,30,2d,\ 39,37,32,32,33,36,36,2d,34,35,31,39,38,00,5a,00,00,00,41,32,32,2d,30,30,30,\ 30,31,00,00,00,00,00,00,00,00,e5,3f,e9,6a,2c,ed,25,35,12,ec,11,c9,8d,01,00,\ 00,00,00,00,37,03,6d,3f,44,22,06,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,31,32,32,32,30,00,00,00,00,00,00,00,dc,0f,\ 00,00,bf,4a,94,6c,80,00,00,00,15,18,00,00,00,00,00,00,00,00,00,00,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,34,79,ca,d7 "LicenseInfo"=hex:71,84,c7,56,a0,d6,10,6e,70,b4,9f,e9,10,1a,1e,7a,01,a4,41,09,\ 25,20,0e,80,83,80,1f,31,27,86,64,1f,31,dc,22,af,f7,7d,aa,e4,2a,b9,e5,e3,6c,\ e2,01,69,85,70,91,be,a7,9f,95,e5 方案2:更换密钥(推荐) 将以下内容复制保存,文件名重命名为.vbs,双击运行然后输入对应密钥
'For WinXP SP1 SP2 ,Windows Server 2003 '*************************************************************************** ON ERROR RESUME NEXT Dim VOL_PROD_KEY if Wscript.arguments.count<1 then VOL_PROD_KEY=InputBox("使用说明(OEM版无效):"&vbCr&vbCr&" 本脚本程序将修改当前 Windows 的序列号。请先使用算号器算出匹配当前 Windows 的序列号,复制并粘贴到下面空格中。"&vbCr&vbCr&"输入序列号(默认为 XP VLK):"
//设置http响应头,告诉浏览器以下载的方式来处理返回的数据,设置中文编码java.net.URLEncoder.encode()
response.setHeader("Content-Disposition", "attachment;filename="+java.net.URLEncoder.encode(filenamestr, "utf-8"));
随着手机技术的发展定位方式也发生了很大的变化。获取手机位置有很多种方式。
第一种:CELL-ID定位原理
通过移动网络获取设备当前所在的Cell信息来获取设备当前位置。当设备位置更新设备会向当前服务小区报告当前位置信息,Cell ID定位的精度随着小区的覆盖范围而变化,从几十米到上百米不等。Cell ID是目前最容易使用的定位方式。只要获取手机访问的基站编号,在通过后台服务得到基站的坐标那就能获得手机的大体位置了。
第二种:AFLT定位原理
AFLT(Advanced Forword Link Trilateration) 是在定位操作时同时监听多个基站的信号,利用信号的延时和强度信号来确定手机到附件基站的距离,最后用三角定位算法计算用户的位置。一般在城市里基站的覆盖往往是重叠没有盲区的。所以手机往往会有多个基站的信息。这也是为什么基站定位城市比农村要准确很多的原因。
第三种:基站和GPS的混合定位(AGPS)
第四种:基站+ WIFI+ GPS的混合定位。
这种定位方式是目前最常用的定位方式,在使用手机地图通常是提示你打开GPS或者Wifi。如果要是在室外打开任意一个选项都可以大大提高定位精度。 特别是打开wifi会瞬间提高定位精度。目前手机地图的定位方式基本都是这样的混合定位方式。原来也很简单就是IP定位,在你手机接入wifi时回获取到路由的硬件地址,如果你手机在线就可以通过这唯一地址得到路由的位置坐标,在通过对wifi的强度信息获取你的距离信息组后提高你的位置精度。
手机查看基站信息的方法
1. Android智能机:在拨打电话界面输入*#*#4636#*#* 查看相应的基站信息,一般为16进制,请选择1进制进行查询
2. IPhone:在拨打电话界面输入*3001#12345#*查看相应的基站信息
查出CID后你可以尝试在 http://www.minigps.net/cellsearch.html 定位一下自己手机的位置。
输入*#*#4636#*#* 选择->Phone information
--------------------- 作者:立玉 来源:CSDN 原文:https://blog.csdn.net/lbsnews/article/details/24660247 方法1:
用浏览器打开http://www.minigps.net/cellsearch.html,然后输入lac和cid信息(mcc和mnc可以填0),如果数据正确就可以获得相应的经纬度
方法2:
发送HTTP请求到http://www.open-electronics.org/celltrack/cell.php?hex=0&lac=<lac>&cid=<cid>,可以获得一个html页面内容,通过正则进行解析,也可以获得经纬度信息
基站定位描述
基站定位一般应用于手机用户,手机基站定位服务又叫做移动位置服务(LBS——Location Based Service),它是通过电信移动运营商的网络(如GSM网)获取移动终端用户的位置信息(经纬度坐标),在电子地图平台的支持下,为用户提供相应服务的一种增值业务。
基站定位的大致原理为:移动电话测量不同基站的下行导频信号,得到不同基站下行导频的TOA(Time of Arrival,到达时刻)或TDOA(Time Difference of Arrival,到达时间差),根据该测量结果并结合基站的坐标,一般采用三角公式估计算法,就能够计算出移动电话的位置。其精度很大程度依赖于基站的分布及覆盖范围的大小,有时误差会超过一公里,实际的位置估计算法需要考虑多基站(3个或3个以上)定位的情况,因此算法要复杂很多。一般而言,移动台测量的基站数目越多,测量精度越高,定位性能改善越明显。
怎样才能基站定位?
基站定位一般应用在手机端,所以必须获取到基站信息才能进行基站的定位;基站信息
包含:MNC,LAC,CID (Cell) 三个参数;如果获取到以上三个参数即可以通过基站数据库,实现对应基站的位置进行定位,直接地图上显示出基站的位置;
-MCC,Mobile Country Code,移动国家代码(中国的为460);
-MNC,Mobile Network Code,移动网络号码(中国移动为00,中国联通为01);
-LAC,Location Area Code,位置区域码;
-CID,Cell Identity,基站编号,是个16位的数据(范围是0到65535)。
如何获取基站信息?
在GSM模块中,可以通过AT指令获取基站信息,以使用UBLOX的GSM模块为例,
当设备注册到移动网络时,按以下步骤即可获取对应的基站信息。
1. 获取MCC和NNC
AT+COPS=3,2 //设置MCC和NNC输出格式为数字
React Router 是完整的 React 路由解决方案
React Router 保持 UI 与 URL 同步。它拥有简单的 API 与强大的功能例如代码缓冲加载、动态路由匹配、以及建立正确的位置过渡处理。今天我们就来大概的看一下这个强大的组件是如何实现的。
react-router为了能实现跨平台的路由解决方案,将react-router分成了三个模块:react-router,react-router-native,react-router-dom三个包,react-router是另外两个模块的基础。这里我们主要分析react-router-dom的基本实现。
react-router源码地址: https://github.com/ReactTraining/react-router
RouterContext react-router使用context实现跨组件间数据传递,所以react-router定义了一个routerContext作为数据源,
// packages/react-router/modules/RouterContext.js import createContext from "mini-create-react-context"; const createNamedContext = name => { const context = createContext(); context.displayName = name; return context; }; const context = createNamedContext("Router"); export default context; 代码非常好理解,定义createNamedContext函数,然后调用它来创建一个context。
Router 我们在使用react-router-dom的使用,经常会用到BroswerRouter和HashRouter两个组件,这两个组件都使用了Router组件,所以所Router组件是基础,我们先来看看Router组件定义
// packages/react-router/modules/Router.js import RouterContext from "./RouterContext"; class Router extends React.Component { static computeRootMatch(pathname) { return { path: "/", url: "
react native 安卓中headerTitle居中对齐 在navigationOptions配置如下
static navigationOptions = ({navigation}) => { return { headerTitle:'储能选择', headerStyle: { backgroundColor: '#42b0fc', alignItems:'center' }, headerTitleStyle: { flex:1, textAlign: 'center' //alignSelf: 'center'navigation3.0版本以下可以直接用这个,3.0以上用上面两句代码 }, headerRight: ( <View/>//如果有返回按钮,加上一个View标签,才能使headerTitle居中 ), }; };
首先基本了解一下DMX512的基本协议
一、 DMX512协议
DMX 是Digital MultipleX 的缩写,意为多路数字传输。DMX512控制协议是美国舞台灯光协会(usITT)于1990年发布的灯光控制器与灯具设备进行数据传输的工业标准,全称是USITTDMX512(1990),包括电气特性、数据协议、数据格式等方面的内容。
每一个DMX 控制字节叫做一个指令帧,称作一个控制通道,可以控制灯光设备的一个或几个功能。一个DMX 指令帧由1个开始位、8个数据位和2个结束位共11位构成,采用单向异步串行传输,如图1所示。
图1 DMX512 定时程序的帧结构(上图)和信息包结构(下图)
图1 中虚线内控制指令中的S 为开始位,宽度为一个比特,是受控灯具准备接收并解码控制数据的开始标志;E为结束位,宽度为两个比特,表示一个指令帧的结束;D0~ D7为8 位控制数据,其电平组合从0000~一l1111111 共有256个状态(对应十进制数的0~255),控制灯光的亮度时,可产生256个亮度等级,0000~ (0)对应灯光最暗,l1111111(255)对应灯光最亮。DMX512指令的位宽(每比特宽度)是4 us,每帧宽度为44 us,传输速率为250 kbps。
一个完整的DMX512信息包(Packet)由一个MTBP位、一个Break 位、一个MAB位、一个SC 和512个数据帧构成。MTBP(Mark TimeBetween Packets)标志着一个完整的信息包发送完毕,是下一个信息包即将开始的“空闲位”,高电平有效。Break为中断位,对应一个信息包结束后的程序复位阶段,宽度不少于两个帧(22 比特)。程序复位结束后应发送控制数据,但由于每一个数据帧的第一位(即开始位)为低电平,所以必须用一个高电平脉冲间隔前后两个低电平脉冲,这个起间隔、分离作用的高电平脉冲即MAB(Mark After Break),此脉冲一到,意味着“新一轮”的控制又开始了。SC(Start Code)意为开始代码帧(图1中的第0帧),和此后到来的数据帧一样,也是由11 位构成,除两个高电平的结束位之外,其他9位全部是低电平,通常将其叫做第0 帧或第0通道(Ch~nel No 0),可理解为一个不存在的通道(Non一~istent Channe1)。
表1 DMX512 信息包定时表
表1 是DMX512 信息包的定时表,表中NS意为Nm Spec~ed,宽度没有严格限制,由程序设计者自行决定,比如MTBP的宽度可以介于0~1秒之间。
调光控制台每发送一个信息包,可以对全部512个受控通道形成一次全面的控制。发送一个信息包的时间大约是23 ms,每秒钟将对所有512个受控通道完成44 次控制,即受控光路的刷新频率44 Hz,如果实际受控通道少于512个,那么刷新频率将相应提高。
根据标准的512协议,其物理连接与传统上的RS485是完全一致的,并没有什么差别,差别只是在协议上的不同,工业上应用的主要是modbus协议,而这里是用512通信协议。
DMX512数据协议是美国舞台灯光协会(USITT)于1990年发布的一种灯光控制器与灯具设备进行数据传输的标准。它包括电气特性,数据协议,数据格式等方面的内容。
512协议规定使用的波特率是250Kbps,而stm32可以支持上Mbps的波特率,所以说这不是什么大问题。
该协议发送的数据帧一共11位,
1位开始位,
8位数据,
2个停止位,无校验位。
根据波特率可以知道,位时间是4us,11位数据供需要44us的时间。当然对于标准的512协议是需要break和mark after break 帧的,break是一个92us的低电平,而mark after break是一个12us的高电平,
512协议必须有break和mark,但是在我们通常的非标准收发中,检测break和mark相对比较困难,如果非要做,耗费的资源也比较多,比如定时器计时,中断等等。如果不是做标准控制器的,完全可以另辟蹊径。
每一串数据的开始都要有一个起始码,也称复位码,其数据为0,但是从开始位数至第十位是0,用来声明数据传输开始,随后包含1-512个数据,也称调光数据,其是标准的数据帧,所以第十位是1,所以我们可以根据这个第十位来进行做文章。大家都知道,一般的单片机,像51,avr等都是支持8-9位数据发送的,所以我们就是用9位数据,
1位停止位,无校验位,通过检测检测第十位,也就是所谓的RB8来进行数据的接收与传输,不需要发送break和mark。
1、发送端 串口设为 9位数据, 1停止位,无校验位,波特率250000 void USART1_Configuration(void) { USART_InitTypeDef USART_InitStructure; USART_InitStructure.
转:openwrt 框架分析link.
阅读目录
openwrt目录结构
main Makefile
第一个逻辑
第二逻辑
目录变量
kernel 编译:
生成firmware
处理vmlinux: Image/BuildKernel
制作squashfs,生成.bin: $(call Image/mkfs/squashfs)
OpenWrt是一个典型的嵌入式Linux工程,了解OpenWrt的Makefile的工作过程对提高嵌入式Linux工程的开发能力有极其重要意义。
OpenWrt的主Makefile文件只有100行,可以简单分为三部分,117行为前导部分,1931为首次执行部分,33~101为再次执行部分。
前导部分
CURDIR为make默认变量,默认值为当前目录。
前导部分主要把变量TOPDIR赋值为当前目录,把变量LC_ALL、LANG赋值为C,并使用变量延伸指示符export,把上述三个变量延伸到下层Makefile。
使用文件使用指示符include引入 ( T O P D I R ) / i n c l u d e / h o s t . m k 。 在 O p e n W r t 的 主 M a k e f i l e 文 件 使 用 了 多 次 i n c l u d e 指 示 符 , 说 明 主 M a k e f i l e 文 件 被 拆 分 成 多 个 文 件 , 被 拆 分 的 文 件 放 在 不 同 的 目 录 。 拆 分 的 目 的 是 明 确 各 部 分 的 功 能 , 而 且 增 加 其 灵 活 性 。 在 前 导 部 分 比 较 费 解 的 是 使 用 w o r l d 目 标 , 在 m a k e f i l e 中 基 本 规 则 为 : T A R G E T S : P R E R E Q U I S I T E S C O M M A N D .
目录 前言smartconfig工作原理beginSmartConfig()stopSmartConfig()smartConfigDone()实例Demo 前言 继上次写智能配网的文章已经过去差不多三个月,中间忙一下其他项目也就没有继续跟进了,不过好在这过程中顺便熟悉了一下硬件开发,今天重拾起来可能会给文章增添更多的营养价值吧。 下面是关于Arduino中ESP8266的SmartConfig一键配网相关记录,以便加深对智能家居一整套工作流程的理解。
smartconfig工作原理 所谓SmartConfig就是手机App端发送包含WIFI用户名以及密码的UDP广播包,智能终端(开启了sniffer混杂模式)的WIFI芯片可以接收到该UDP包,通过接收到的UDP包解密出WIFI用户名密码,然后智能硬件配置收到的用户名密码到指定的WIFI上(详情见)。
beginSmartConfig() 函数说明:
/** * 启动配网模式 * @return bool 是否启动配网模式成功 */ bool beginSmartConfig(); stopSmartConfig() 函数说明:
/** * 停止Smartconfig * @return bool 是否停止配网模式成功 */ bool stopSmartConfig(); smartConfigDone() 函数说明:
/** * 查找状态看是否配网完成 * @return bool 是否启动配网模式成功 */ bool smartConfigDone(); 实例 我这里是直接使用的ESP8266-12F的开发板,上面集成了Arduino,可直接通过USB进行程序烧录,减少ESP8266和Arduino板子之间的连接工作,大大减少了开发工作量。
如果你不是直接使用开发板,或者不知道如何在arduino中搭建ESP8266插件,可参见:https://www.jianshu.com/p/c6f8b59762b6, 当然ESP8266开发板某宝上一搜一大把,价格大多在20-100不等;
在这个例子中我们只需要直接将板子用USB和电脑连接上即可,如果是第一次使用Arduino可能需要安装驱动(详情见);
实例代码:
void setup() { //开启串口 Serial.begin(115200); //启动配网模式 smartConfig(); } void loop() { delay(100); Serial.println("loop"); } /** * 一键配网关键代码 */ void smartConfig() { WiFi.
TEXT类型读取超过2M的字符串的时候报错
Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. 关于SQLite 不同类型存储数据大小的限制 1、CHAR。CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义char(10),那么不论你存储的数据是否达到了10个字节,都要占去10个字节的空间,不足的自动用空格填充。
2、VARCHAR。存储变长数据,但存储效率没有CHAR高。如果一个字段可能的值是不固定长度的,我们只知道它不可能超过10个字符,把它定义为 VARCHAR(10)是最合算的。VARCHAR类型的实际长度是它的值的实际长度+1。为什么“+1”呢?这一个字节用于保存实际使用了多大的长度。从空间上考虑,用varchar合适;从效率上考虑,用char合适,关键是根据实际情况找到权衡点。
3、TEXT。text存储可变长度的非Unicode数据,最大长度为2^31-1(2,147,483,647)个字符。
4、NCHAR、NVARCHAR、NTEXT。这三种从名字上看比前面三种多了个“N”。它表示存储的是Unicode数据类型的字符。我们知道字符中,英文字符只需要一个字节存储就足够了,但汉字众多,需要两个字节存储,英文与汉字同时存在时容易造成混乱,Unicode字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符都用两个字节表示,即英文字符也是用两个字节表示。nchar、nvarchar的长度是在1到4000之间。和char、varchar比较起来,nchar、nvarchar则最多存储4000个字符,不论是英文还是汉字;而char、varchar最多能存储8000个英文,4000个汉字。可以看出使用nchar、nvarchar数据类型时不用担心输入的字符是英文还是汉字,较为方便,但在存储英文时数量上有些损失。
问题 理论上,TEXT可以存储的字符串长度为2^31-1(2,147,483,647)个字符,按英文字符来算的话就是 2G大小
但是,Cursor 在获取超过2M 大小数据的时候,会报异常。
所以处理方式用字符串截取的方式来处理
select LENGTH(SHAPE) from SURVEY_RECORD where TBLX = 'SDDLTB' and TBBH = '6950' ; select substr(SHAPE,0,1048576) from SURVEY_RECORD where TBLX = 'SDDLTB' and TBBH = '6950' ; select substr(SHAPE,1048576,2097152) from SURVEY_RECORD where TBLX = 'SDDLTB' and TBBH = '6950' ; 使用到的函数的说明:
一、软件环境 Django + DRF
VUE
报错信息:
has been blocked by CORS policy: NO 'Access-Control-Allow-Origin' header is present on the reauested resource.
二、同源策略 1、浏览器的同源策略 浏览器发现ip或端口是不一样的,就会认为存在风险,会进行拦截。
除非后端告诉浏览器允许。
2、简单请求和复杂请求 HTTP方法是下列方法之一
HEAD, GET,POST
HTTP头信息不超出以下几种字段
Accept, Accept-Language, Content-Language, Last-Event-ID
Content-Type只能是下列类型中的一个
application/x-www-from-urlencoded
multipart/form-data
text/plain
任何一个不满足上述要求的请求,即是简单请求。
任何一个不满足,即会被认为是复杂请求~~
两者区别:复杂请求会先发出一个预请求,我们也叫预检,OPTIONS请求
预检的话,请求发出前就会被拦截。
所以drf发送json数据,就是复杂请求。
三、添加响应头解决跨域 解决思路就是告诉浏览器:不进行拦截
这里是django后端,实现如下:
Django 中间件加响应头 MIDDLEWARE = [ ... 'middlewares.Mycors', ] middlewares/Mycors.py
from django.utils.deprecation import MiddlewareMixin class MyCors(MiddlewareMixin): def process_response(self, request, response): response["Access-Control-Allow-Origin"] = "*" if request.
在一次爬虫下载图片的过程中,遇到服务器返回403,然后寻找解决办法,解决办法如下:
1.一般造成403的原因是权限设置问题,也就是没有权限造成的,因此这里直接添加信任权限即可:
webclient.Credentials = CredentialCache.DefaultCredentials; // 添加授权证书 2.分析Reques tHeaders
可以看到在requet中,有host,cookie等需要设置的内容,因此加上相应的内容即可:
给webclient添加头信息
WebClient mywebclient = new WebClient(); mywebclient.Credentials = CredentialCache.DefaultCredentials; // 添加授权证书 mywebclient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"); mywebclient.Headers.Add("Host", "biz.touchev.com"); mywebclient.Headers.Add("Cookie", "UM_distinctid=16bb1d9972eab2-0ec4ae521bb726-3e385b04-1fa400-16bb1d9972f9b8; PHPSESSID=upN0hwQw8FlkIm_Y7uegI45AB8qRVRDS7yq-YGrQ5o6mm6Hc_BSqQg7hNLQ6sr8x; Hm_lvt_6dba01603aa724759d9c4ea0dddd9b72=1562056956,1562816935; CNZZDATA1273105019=948668930-1562055616-%7C1562909757; Hm_lpvt_6dba01603aa724759d9c4ea0dddd9b72=1562914189"); mywebclient.DownloadFile(url, desPath); 运行,ok~
题外知识:
有关HTTP头完整、详细的说明,请参见 http://www.w3.org/Protocols/ 的HTTP规范。
1. RequestHeader分析:
Accept:浏览器可接受的MIME类型。 Accept-Charset:浏览器可接受的字符集。 Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip。Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间。
Accept-Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到。 Authorization:授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中。 Connection:表示是否需要持久连接。如果Servlet看到这里的值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后在正式写出内容之前计算它的大小。 Content-Length:表示请求消息正文的长度。 Cookie:这是最重要的请求头信息之一 From:请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。 Host:初始URL中的主机和端口。 If-Modified-Since:只有当所请求的内容在指定的日期之后又经过修改才返回它,否则返回304“Not Modified”应答。 Pragma:指定“no-cache”值表示服务器必须返回一个刷新后的文档,即使它是代理服务器而且已经有了页面的本地拷贝。 Referer:包含一个URL,用户从该URL代表的页面出发访问当前请求的页面。 User-Agent:浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。 UA-Pixels,UA-Color,UA-OS,UA-CPU:由某些版本的IE浏览器所发送的非标准的请求头,表示屏幕大小、颜色深度、操作系统和CPU类型。 每个标头独占一行, 最后必须要有一个空行。有关HTTP头完整、详细的说明,请参见http://www.
TX初始化过程
初始化步骤 24L01相关寄存器
1)写 Tx 节点的地址 TX_ADDR
2)写 Rx 节点的地址(主要是为了使能 Auto Ack) RX_ADDR_P0
3)使能 AUTO ACK EN_AA
4)使能 PIPE 0 EN_RXADDR
5)配置自动重发次数 SETUP_RETR
6)选择通信频率 RF_CH
7)配置发射参数(低噪放大器增益、发射功率、无线速率) RF_SETUP
8 ) 选择通道0 有效数据宽度 Rx_Pw_P0
9)配置 24L01 的基本参数以及切换工作模式 CONFIG Rx初始化过程
RX初始化步骤 24L01相关寄存器
1)写 Rx 节点的地址 RX_ADDR_P0
2)使能 AUTO ACK EN_AA
3)使能 PIPE 0 EN_RXADDR
4)选择通信频率 RF_CH
5) 选择通道0 有效数据宽度 Rx_Pw_P0
6)配置发射参数(低噪放大器增益、发射功率、无线速率 RF_SETUP
7)配置 24L01 的基本参数以及切换工作模式 CONFIG
一对一通讯还是很简单的,4个配置一定要配置对,地址,信道,通讯频率,传输速率一定要一致。
一切为了实现利用ros通过串口控制小车简单运动
基于ROS平台的STM32小车-4-上位机控制器
https://blog.csdn.net/weixin_39752599/article/details/86552511 下载串口通信的ROS包
cd ~/catkin_ws/src git clone https://github.com/ncnynl/serial.git 下载键盘控制的ROS包
cd ~/catkin_ws/src git clone https://github.com/ncnynl/teleop_twist_keyboard.git 进入下载好的ROS包的文件夹,选中 keyboard_teleop_zbot.py (没有此文件,只有teleop_twist_keyboard.py???),右键->设为可执行文件。
最后编译
cd ~/catkin_ws catkin_make 在上位机上搭建一个控制器:
新建 base_controller ROS 包:
$ cd ~/catkin_ws/src $ catkin_create_pkg base_controller roscpp $ cd catkin_ws/src/base_controller $ mkdir src $ touch src/base_controller.cpp $ gedit src/base_controller.cpp 基于串口通信的ROS小车基础控制器,功能如下:
1.实现ros控制数据通过固定的格式和串口通信,从而达到控制小车的移动
2.订阅了/cmd_vel主题,只要向该主题发布消息,就能实现对控制小车的移动
3.发布里程计主题/odm 串口通信说明:
1.写入串口 (1)内容:左右轮速度,单位为mm/s (2)格式:10字节,[右轮速度4字节][左轮速度4字节][结束符"\r\n"2字节]
2.读取串口 (1)内容:小车x,y坐标,方向角,线速度,角速度,单位依次为:mm,mm,rad,mm/s,rad/s (2)格式:21字节,[X坐标4字节][Y坐标4字节][方向角4字节][线速度4字节][角速度4字节][结束符"\n"1字节]
base_control.cpp代码如下:
#include "ros/ros.h" //ros需要的头文件 #include <geometry_msgs/Twist.h> #include <tf/transform_broadcaster.h> #include <nav_msgs/Odometry.h> //以下为串口通讯需要的头文件 #include <string> #include <iostream> #include <cstdio> #include <unistd.
定义和用法 onchange 事件会在域的内容改变时发生。
语法 οnchange="SomeJavaScriptCode" 参数描述SomeJavaScriptCode必需。规定该事件发生时执行的 JavaScript。 支持该事件的 HTML 标签: <input type="text">, <select>, <textarea> 支持该事件的 JavaScript 对象: fileUpload, select, text, textarea 实例 1 在本例中,我们将在用户改变输入域内容时执行 JavaScript 代码:
<html> <head> <script type="text/javascript"> function upperCase(x) { var y=document.getElementById(x).value document.getElementById(x).value=y.toUpperCase() } </script> </head> <body> 输入您的姓名: <input type="text" id="fname" onchange="upperCase(this.id)" /> </body> </html>
/******************************************************************************************
* 版权声明
* 本文为本人原创,本人拥有此文的版权。鉴于本人持续受益于开源软件社区,
* 本人声明:任何个人及团体均可不受限制的转载和复制本文,无论是否用于盈利
* 之目的,但不得修改文章内容,并必须在转载及复制时同时保留本版权声明,否
* 则为侵权行为,本人保留追究相应主体法律责任之权利。
* speng2005@gmail.com
* 2019-7
******************************************************************************************/
近日在win10上配置python 3.6开发环境,经常需要安装各种第三方包。由于未使用anconda等环境管理工具进行安装,所以经常碰到一类非常恼人的错误信息:
ImportError: DLL load failed: 找不到指定的程序。
这么一个没什么有用信息的报错,令人非常恼火。其实,这并非是python为了省事,简单报个错,而是python也只能得到一个简单的错误代码和一句干巴巴的错误信息,再也没有其他有用信息了。
难道真没有详细错误信息了吗?
还真有,不过不是一般人能想到使用的。这就是Gflags工具(看来又要用它了)。
Gflags是微软为windows平台调试应用程序错误的利器。它来自windows sdk开发工具包。
Gflags 官方参考:https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/gflags-commands
Gflags可以设置一个特殊参数,使得目标程序下次启动后,windows的dll加载器ldr会打印加载过程中的详细调试信息。不过,这个调试信息需要在vistual studio工具attach到目标程序之后,才能在其output窗口中看到。
此处Gflags用法:
假设目标程序是testProject1.exe
cmd中执行命令:
gflags.exe -i testProject1.exe +sls 可实现下次启动testProject1.exe后,用vistual studio连接到testProject1.exe,即可在output窗口看到windows的ldr打印的一大堆调试信息。仔细看这些输出,你肯定会找到为什么dll加载失败了。
那么脑洞再开一下,为什么Gflags设置以后就有ldr的详细信息了?经过一番探究,原来是windows的dll加载器ldr核心代码就在ntdll.dll中,在该dll的LdrLoadDll()函数就是实现具体dll加载过程的入口函数。该dll中有一个未公开的ShowSnap全局变量,该变量不同的bit位可以提供不同的debug功能支持。只要ShowSnap的最低位为1,就可以实现打印ldr的详细调试信息。gflags.exe上述命令设置的目的也就是用来影响目标程序testProject1.exe启动后,系统自动设置ShowSnap全局变量的值,使其最低位为1。
那为什么ldr打印的调试信息必须要在vistual studio中才能看到?因为ldr打印调试信息不是普通的printf,而是以异常信息来实现的,具体来说就是通过调用ntdll.dll中的RtlRaiseException()来实现的,在异常信息中设置异常代码为DBG_PRINTEXCEPTION_C,然后vistual studio以调试器的身份捕获该异常并显示ldr抛出的调试信息。
如果对目标程序调试完毕,最好使用命令:
gflags.exe -i testProject1.exe -sls 来关闭ldr打印调试信息,以提高性能。
以笔者遇到的情况,在搭建基于pytorch的人工智能项目环境时,在import torch时就失败了,出现了上面的无用错误提示。为了找到问题原因,就需要使用上述方法。为方便调试,写了如下测试脚本test_torch.py:
import torch print(torch.__version__) 然后执行如下命令开启ldr打印调试信息功能:
gflags.exe -i python.exe +sls 接着运行py脚本:
python.exe d:\test\test_torch.py 然后打算用vistual studio来attach时,发现上面代码迅速执行结束,根本没有机会attach。所以这时需要启用python的debugger来让py脚本中断执行:
python.exe -m pdb d:\test\test_torch.
https://pan.baidu.com/s/1AYpTxklTRXCpqGV6hD3UzQ
提取码:j7ku
<!DOCTYPE html> <html> <head> <title>Window Title</title> </head> <body> <p>Test your mouse on me!</p> <script> const p = document.querySelector('p'); p.onmouseover = logMouseOver; p.onmouseout = logMouseOut; function logMouseOver() { p.innerHTML = 'Your mouse is over me.'; } function logMouseOut() { p.innerHTML = 'Your mouse is not over me.'; } </script> </body> </html>
问题描述: 在设置外部客户端连接mysql数据后,出现下面的问题:
1,执行mysql -u root –p,输入密码后一直提示ERROR 1045 (28000): Access denied for user'root'@'localhost' (using password: YES),
、
2,用mysql可以进入数据库,执行shoe databases;后数据库显示不全
正常的应该默认有4个
问题原因: 原来是MySQL数据库的user表里,存在用户名为空的账户即匿名账户,导致登录的时候是虽然用的是root,但实际是匿名登录的,通过错误提示里的''@'localhost'可以看出来。
解决办法:
因此只需要把user表中的匿名用户删除即可解决这两个问题。
1、# vi /etc/my.cnf
在[mysqld]块最后面加上skip-grant-tables,这样重启服务后登陆MySQL无需密码,保存退出vim
2、# service mysqld restart
重启服务
3、# mysql -u root -p
回车直接进入mysql
4、mysql> use mysql ;
5、mysql>delete from user where user=''; 删除空用户前
删除空用户后
6、mysql>flush privileges;
刷新权限表
7、把第一步中my.cnf文件中加上的那一行去掉,再次重启服务即可。
8,正常登录:
9,客户端也可正常登录
总结:每个人遇到的问题可能不同,但是解决这个问题的本质就是想办法删掉mysql.user表下的空用户就解决问题了。 delete from user where user='';
废话不多说,直接上语句。
1.not in 写法:
select * from table where (field1,field2,field3) not in (select field1,field2,field3 from table)
2.in 写法:把上述例子中的 not in 换成 in 即可。
3.not exists 写法:
select * from table t1 where not exists (select field1,field2,field3 from table t2 and t1.field1=t2.field1 and t1.field2=t2.field2 and t1.field3=t2.field3 )
4.exists 写法:把上述例子中的 not exists 换成 exists 即可。
之前在做C++binder通信时,需要把一个apk作为服务端,里面对服务添加,用到了很多底层代码,系统签名
加入android:sharedUserId="android.uid.system"这个属性。使用eclipse编译出未加签名的apk文件,但是这个apk文件是不能用的。
会报错:[2019-07-22 15:14:30 - AndroidIPC] Installation error: INSTALL_FAILED_SHARED_USER_INCOMPATIBLE [2019-07-22 15:14:30 - AndroidIPC] Please check logcat output for more details. [2019-07-22 15:14:30 - AndroidIPC] Launch canceled!使用系统秘钥进行重新签名(linux平台下的操作)
3.1、将eclipse的apk拷贝到linux平台
3.2、java -jar out/host/linux-x86/framework/signapk.jar build/target/product/security/platform.x509.pem build/target/product/security/platform.pk8 AndroidIPC.apk AndroidIPCsigned.apk通过Shared User id,拥有同一个User id的多个APK可以配置成运行在同一个进程中。那么把程序的UID配成android.uid.system,也就是要让程序运行在系统进程中 ADD: linux指令:cp 文件或文件夹拷贝
银行客户流失分析 摘要研究背景研究目标分析流程 数据探索与预处理数据探索1、定量变量初探2、分类指标分布情况3、目标变量分布 数据预处理数据清洗1、删除不相关变量2、异常值处理 数据变换1、字符型变量的量化2、连续特征离散化。3、样本不均衡处理4、虚拟变量变换5、特征标准化 特征选择 数据建模和调参模型评价XGBoost模型介绍、调参及评估XGBoost模型介绍XGBoost模型原理XGBoost模型优点 XGBoost模型调参模型评估 关于挽留和关怀客户的建议特征重要性建议 python编程 摘要 摘要
随着互联网金融的异军突起,银行业的竞争愈加激烈,防止客户流失和挽留老客户成为各大银行关心的重要问题。本文首先根据已有数据集对各特征进行描述性统计分析,初步了解数据;之后进行数据预处理,包括数据清洗,数据变换、特征选择;再后用SVM、LR、朴素贝叶斯、决策树、RF、XGBoost、LM神经网络进行建模,通过不同性能度量,选出XGBoost为表现最好的模型并进行调参;最后,根据描述性统计和特征重要性为银行挽留客户提出建议。
关键词:客户流失;数据预处理;XGBoost;调参;建议
研究背景 银行客户流失是指银行的客户不再继续参与原业务、不再重复购买或者终止原先的产品或者服务。近年来,随着互联网金融的异军突起和传统银行业的竞争加剧,银行发展自身潜力、吸引优质顾客、防止客户流失就显得格外重要。研究表明,发展一位新客户所花费的成本要比维持一位老客户的成本多达5到6倍。所以说,在客户流失后,如果企业要去重新发展新客户所需要的成本是巨大的,且大多数新用户产生的利润不如老用户。因此,不管是哪个行业都越来越重视客户流失管理。预测潜在的流失客户、有效挽留和关怀客户是各个企业关心的重要问题之一。
研究目标 1、通过确定客户流失模型,有效预测客户的流失情况。
2、通过预测模型的建立,提出相应建议提高用户的活跃度,实现挽留关怀客户的有效性,降低开展挽留关怀工作的成本。
分析流程 客户流失数据 数据探索与预处理 数据清洗 数据变换 特征选择 建模 训练样本 测试样本 模型评价 数据探索与预处理 本节首先观察样本数据,初步了解属性特征,对各属性进行描述性统计分析,初步探索各属性与客户流失情况的关系;其次进行数据预处理工作,包括异常值处理,数据变换,数据规约等;之后将样本划分为训练集和测试集,观察客户流失情况样本是否均衡,不均衡时需要对训练样本进行均衡化处理;最后,对训练集和测试集进行标准化处理。
数据探索 本次所使用的数据集是某欧洲银行的数据。数据集一共包含了14个变量,10000个样本,不包含缺失值。本数据集可从superdatascience官网下载。首先先来观察数据情况。 图1 数据集变量预览
在图1展示的数据集中,从左到右,数据集所具有的的变量有编号、用户ID、姓名、信用分、地区、性别、年龄、用户时长(使用银行产品时长)、存贷款情况、使用产品数量、是否有信用卡、是否为活跃用户、估计收入、是否已流失。将数据集特征进行汇总,由表1可以清楚地看出特征变量名称和属性。
表1 数据集特征汇总
我们从表1可以看到,数据集一共包含14个变量,其中第14个变量就是我们的目标变量,目标变量定义的是是否已经流失的分类变量,从而确定了本次数据挖掘的目标是分类。除了目标变量外,特征属性中有7个分类变量,其中有5个是字符类型的,这意味着在数据预处理时首先要处理这些变量才能做下一步分析。其余6个是数值变量,我们接下来要注意考虑数值变量是否存在异常值,是否需要进行数据变换。
下面对各变量首先进行描述性统计分析,观察变量分布情况,进一步了解数据。
1、定量变量初探 本小节主要是通过绘制定量变量的频数分布图来观察变量的分布情况,初步了解各变量分布。
图2-1 CreditScore-信用得分频数分布 图2-2 Age-年龄频数分布 图2-3 Tenure-客户使用年数分布 图2-4 Balance-客户存贷款情况 图2-5 NumOfProducts-拥有产品数量 图2-6 EstimateSalary-估计收入 图2 定量变量频数分布图 总体来看图2-1,对于信用分这个属性来说,流失和非流失总体呈现出一个偏正态分布,信用分在650-700之间达到峰值。由图2-2可以看出,年龄呈现出一个偏左态分布。该银行35到40岁的客户最多,在60岁以上的客户很少。且给银行的目标用户大部分年龄在25到45岁之间,比较符合多数银行客户年龄的分布情况。对于该银行,图2-3用户使用年数在1到9年的分布均匀,使用10年的人数最多,使用1年的人数较少。我们可以初步猜测该银行忠诚客户较多,但是在发展新客户方面不够重视或者策略需要调整。;对于客户存贷款情况,该样本数据显现的都是存贷款大于0的情况。从图中可以看出,存款在25000以下的占据大部分。在存款大于25000呈现正态分布。在持有产品数方面,该银行大多数用户使用银行的产品数量为1个或2个,拥有3个或4个产品的极少。说明该银行的产品只有少数具有吸引力,银行应该实施相应措施激励用户使用该银行产品。从图2-6可以看出,该银行客户估计收入在0到200000之间,且不同收入客户分布均匀,猜测该银行并没有清晰的目标客户定位,对不同收入层的客户效用没有差别。
2、分类指标分布情况 对于分类指标,这里展示了不同指标分类的频数分布情况,同时展示了在每种类别下客户流失情况。
图3-1 地区分布和流失情况 图3-2 性别分布和流失情况 图3-3 信用卡分布和流失情况 图3-4 活跃用户分布和流失情况 图3 定类变量频数分布图 图3-1中,在地区这个属性可以看出,样本数据集客户来自三个国家:法国、德国、西班牙。该银行法国用户最多,德国和西班牙客户数量几乎相等,但从流失情况来看,德国用户的流失率明显高过其他两国。从性别来看,图3-2显示,银行的男性用户高于女性,但是女性的流失率要高过男性。在客户是否拥有信用卡来看(图3-3),该银行70%的客户有信用卡,没有信用卡客户的流失率在20%以上,有信用卡的流失率在16%。使用该银行信用卡的用户忠诚度更高。由图3-4知,该银行的活跃客户稍高于非活跃用户,活跃用户的流失率明显低于非活跃用户,这也说明活跃客户较非活跃客户忠诚度更高。
文章目录 概述一、CGAN1、基本思想2、模型简介3、 应用 二、DCGAN1、基本思想2、模型简介 三、WGAN1、模型解析2、模型优点 四、LSGAN1、基本思想2、模型解析 概述 自从Goodfellow2014年提出这个想法之后,生成对抗网络(GAN)就成了深度学习领域内最火的一个概念,包括LeCun在内的许多学者都认为,GAN的出现将会大大推进AI向无监督学习发展的进程。
于是,研究GAN就成了学术圈里的一股风潮,几乎每周,都有关于GAN的全新论文发表。而学者们不仅热衷于研究GAN,还热衷于给自己研究的GAN起名,比如什么3D-GAN、BEGAN、iGAN等;GAN千奇百怪、应有尽有,形成了GANs的动物园。
下边,就来讨论一些比较经典的GAN架构的文章。
一、CGAN 1、基本思想 在原始GAN网络中,与其他生成式模型相比,GAN这种竞争的方式不再要求一个假设的数据分布,即不需要formulate p(x),而是使用一种分布直接进行采样sampling,从而真正达到理论上可以完全逼近真实数据,这也是GAN最大的优势。然而,这种不需要预先建模的方法缺点是太过自由了,对于较大的图片,较多的 pixel的情形,基于简单 GAN 的方式就不太可控了。为了解决GAN太过自由这个问题,一个很自然的想法是给GAN加一些约束,于是便有了Conditional Generative Adversarial Nets(CGAN)。
生成器和判别器都以某些额外信息y为条件,即把生成对抗网络扩展到条件模型。y可以是任何类型的辅助信息。CGAN可以通过将y作为附加输入,馈入判别器和生成器来执行调节。
2、模型简介 条件生成对抗网络(CGAN)是对原始GAN的一个扩展,生成器和判别器都增加额外信息 y为条件, y 可以使任意信息,例如类别信息,或者其他模态的数据。如 Figure 1 所示,通过将额外信息 y 输送给判别模型和生成模型,作为输入层的一部分,从而实现条件GAN。在生成模型中,先验输入噪声 p ( z ) p(z) p(z) 和条件信息 y y y 联合组成了联合隐层表征。对抗训练框架在隐层表征的组成方式方面相当地灵活。类似地,CGAN 的目标函数是带有条件概率的二人极小极大值博弈(two-player minimax game ):
CGAN的网络结构:
3、 应用 1、CGAN可以把类别标签当作条件,生成是具有该类别的图像。
在MNIST上以类别标签为条件(one-hot编码)训练条件GAN,可以根据标签条件信息,生成对应的数字。生成模型的输入是100维服从均匀分布的噪声向量,条件变量y是类别标签的one hot编码。噪声z和标签y分别映射到隐层(200和1000个单元),在映射到第二层前,联合所有单元。最终有一个sigmoid生成模型的输出(784维),即28*28的单通道图像。
判别模型的输入是784维的图像数据和条件变量y(类别标签的one hot编码),输出是该样本来自训练集的概率。
2、CGAN广泛用于多模态(图像、文本等为不同模态)学习的图像自动标注
下图为多模态的结果展示,第一列为图像,第二列为用户标注,将第一列第二列输入CGAN生成第三列的标签。
二、DCGAN 1、基本思想 这是第一次在GAN中使用卷积神经网络并取得了非常好的结果。之前,CNN在计算机视觉方面取得了前所未有的成果。但在GAN中还没有开始应用CNNs。Alec Radford,Luke Metz,Soumith Chintala等人“Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks”提出了DCGAN。这是GAN研究的一个重要里程碑,因为它提出了一个重要的架构变化来解决训练不稳定,模式崩溃和内部协变量转换等问题。从那时起,基于DCGAN的架构就被应用到了许多GAN架构。
邮件发送错误:503 Error: need EHLO and AUTH first 问题描述问题原因解决方案 问题描述 2019-07-21 16:14:00.449 ERROR 9668 — [pool-1-thread-1] c.w.i.c.m.s.i.EmailMessageServiceImpl : Failed messages: com.sun.mail.smtp.SMTPSendFailedException: 503 Error: need EHLO and AUTH first !
;
nested exception is:
com.sun.mail.smtp.SMTPSenderFailedException: 503 Error: need EHLO and AUTH first !
org.springframework.mail.MailSendException: Failed messages: com.sun.mail.smtp.SMTPSendFailedException: 503 Error: need EHLO and AUTH first !
;
nested exception is:
com.sun.mail.smtp.SMTPSenderFailedException: 503 Error: need EHLO and AUTH first !
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:490) ~[spring-context-support-5.1.6.RELEASE.jar:5.1.6.RELEASE]
文章目录 概述1、什么是GAN?2、发展历史 一、GAN模型1、GAN的基本思想2、GAN的基本模型 二、 GAN的训练三、存在的问题问题一问题二问题三 四、项目实战 概述 1、什么是GAN? 生成对抗网络简称GAN,是由两个网络组成的,一个生成器网络和一个判别器网络。这两个网络可以是神经网络(从卷积神经网络、循环神经网络到自编码器)。我们之前学习过的机器学习或者神经网络模型主要能做两件事:预测和分类,这也是我们所熟知的。那么是否可以让机器模型自动来生成一张图片、一段语音?而且可以通过调整不同模型输入向量来获得特定的图片和声音。例如,可以调整输入参数,获得一张红头发、蓝眼睛的人脸,可以调整输入参数,得到女性的声音片段,等等。也就是说,这样的机器模型能够根据需求,自动生成我们想要的东西。因此,GAN 应运而生!
2、发展历史 生成对抗网络是由Ian Goodfellow等人于2014年在论文《Generative Adversarial Networks》中提出的。学术界公开接受了GAN,业界也欢迎GAN。GAN的崛起是不可避免的。
随着《Generative Adversarial Networks》提出后,GAN产生了广泛流行的架构,如DCGAN,StyleGAN,BigGAN,StackGAN,Pix2pix,Age-cGAN,CycleGAN。这些架构展示了非常有前途的结果。而随着GAN在理论与模型上的高速发展,它在计算机视觉、自然语言处理、人机交互等领域有着越来越深入的应用,并不断向着其它领域继续延伸。因此,本文将对GAN的理论与其应用做一个总结与介绍。
一、GAN模型 1、GAN的基本思想 GAN受博弈论中的零和博弈启发,将生成问题视作判别器和生成器这两个网络的对抗和博弈:生成器从给定噪声中(一般是指均匀分布或者正态分布)产生合成数据,判别器分辨生成器的的输出和真实数据。前者试图产生更接近真实的数据,相应地,后者试图更完美地分辨真实数据与生成数据。由此,两个网络在对抗中进步,在进步后继续对抗,由生成式网络得的数据也就越来越完美,逼近真实数据,从而可以生成想要得到的数据(图片、序列、视频等)。
如果将真实数据和生成数据服从两个分布,那么如图所示:
图中,蓝色虚线为判别分布D,黑色许虚线为真实的数据分布 P d a t a P_{data} Pdata,绿色实线为生成分布 P g P_{g} Pg。GAN从概率分布的角度来看,就是通过D来将生成分布推向真实分布,紧接着再优化D,直至到达图(d)所示,到达Nash均衡点,从而生成分布与真实分布重叠,生成极为接近真实分布的数据。
2、GAN的基本模型 以图片为例,真实图片集的分布 P d a t a ( x ) P_{data}{(x)} Pdata(x), x x x 是一个真实图片,可以想象成一个向量,这个向量集合的分布就是 P d a t a P_{data} Pdata。我们需要生成一些也在这个分布内的图片,如果直接就是这个分布的话,很难做到。
现在有的 generator 生成的分布可以假设为 P G ( x ; θ ) P_G(x;θ) PG(x;θ),这是一个由 θ θ θ 控制的分布, θ θ θ 是这个分布的参数(如果是高斯混合模型,那么 θ θ θ 就是每个高斯分布的平均值和方差)。
使用ESXi进行虚拟机复制非常简单,第一步是导出OVF 和 VMDK 文件,关闭虚拟机,然后选择“导出”即可。
第二步是导入OVF和VMDK文件,操作如下:
在 VMware Host Client 清单中右键单击主机,然后选择创建/注册虚拟机。 新建虚拟机向导将打开。
在该向导的“选择创建类型”页面上,选择从 OVF 或 OVA 文件部署虚拟机,然后单击下一步。 如果在使用ESXi进行复制虚拟机的时候,出现“esxi 复制虚拟机 缺少所需的磁盘镜像”的报错,解决办法是在导出的时候断开虚拟机的CD适配器即可。
Andriod AOA协议通信总结 Android从3.1版本可开始引进了对 AOA协议 ( Android Open Accessory Protocol) 的支持,这是一种允许外部USB硬件与Android设备进行交互的特殊Accessory模式。
Android 开放配件 (AOA) 支持功能可让外部 USB 硬件(Android USB 配件)与处于配件模式下的 Android 设备进行交互。当某台 Android 设备处于配件模式时,所连接的配件会充当 USB 主机(为总线供电并列举设备),而 Android 设备则充当 USB 配件。
Android USB 配件专门用于和 Android 设备相连。这些配件遵循 AOA 要求,从而能够检测到支持配件模式的 Android 设备,并且必须提供 500 毫安(电压为 5 伏)的充电电流。之前发布的部分 Android 设备只能充当 USB 设备,无法发起与外部 USB 设备的连接。AOA 支持功能打破了这一局限,让您能够构建可以与各种 Android 设备建立连接并与其进行交互的配件。
USB accessory overview USB accessory mode allows users to connect USB host hardware specifically designed for Android-powered devices. The accessories must adhere to the Android accessory protocol outlined in the Android Accessory Development Kit documentation.
文章目录 PPWOW (Player vs Player World Of Warcraft)开设的目的是为怀旧玩家提供一个纯公益性的80级巫妖王之怒虚拟交友社区认证服务器(authserver)公共区域世界服务器(public zone server)副本区域服务池(instance server pool)战场区域服务器(battleground server)拍卖行服务器(auctionhouse server)基础worldserver(world server)PPWOW网站功能服务器运行模式 PPWOW (Player vs Player World Of Warcraft)开设的目的是为怀旧玩家提供一个纯公益性的80级巫妖王之怒虚拟交友社区 服务器使用了C++语言开发,网络模块使用ACE库,数据采用mysql存储,redis缓存地图和生物,玩家的线程保存在内存中。服务器使用了pthread多线程框架,可以有效的利用多核cpu的处理能力。同时服务器开启了A*寻路算法,怪物和移动路线全部基于地图tile进行计算。最大限度还原了暴雪的真实游戏体验。接下来,将为你逐一介绍服务端技术结构。
认证服务器(authserver) 认证服务器作为单独运行的服务,主要功能是对游戏账号进行认证,玩家客户端使用openssl加密,通过验证后,authserver将把服务器各网管地址发送给客户端,同时附带服务器分区的认证信息和玩家分别在哪些区有多少角色的信息。
与暴雪的battle net account相似 ,authserver可以为跨区的服务器网管提供认证。多个区可以共用一个authserver,达到battle net的效果;authserver开启之后,需要与所有的游戏区域网关通信,沟通获取认证token;账号的安全信息,都由authserver负责,包括记录了在不同游戏分区玩家账号的权限等级;authserver采用 **RBAC(role based access control)**权限管理方式,可以根据不同游戏区域自由定义玩家的角色,比如不同的GM等级;authserver控制着账号级别的封号、禁言;authserver采用 TCP 协议进行通信;authserver支持多线程,每1000个客户端连接增加一个线程。有着非常优异的性能;authserver在完成认证传递token之后会与客户端断开,不用长时间与客户端连接,只有有需要的时候才连接。authserver支持玩家认证队列(即排队); 公共区域世界服务器(public zone server) 公共区域世界服务器主要为4个地图提供了世界空间:东部王国、卡利姆多、外域、诺森德。对于同一个游戏区域,可以根据线上人数的多少来配置公共区域的实例数量,一般情况下,将4个区域运行在同一个进程中即可。但对于人数较多的服务器可以拆分为每一个大陆一个服务实例,即每一个大陆单独作为服务开启,需要像autherserver注册单独的网关地址。
公共区域服务器继承自世界服务器(worldserver),一个世界服务器支持多个线程(thread)。其包含了地图容器、entity容器(包括了怪物creature 物体object)以及AI调度。世界服务器在启动的时候会载入指定区域的地图mesh数据、区域触发(area trigger)、坐标集合(map data)、建筑物及地形阻隔(vmap)等信息。而entry容器会载入所有需要在地图生成的生物和物体信息,AI调度则是一个公用的行为策略指令集合(core ai / script ai / event ai),可以指派给任一一个entity。
由于地图mesh、区域触发、地图坐标集合、建筑物阻隔等数据容量很大,是非常占用内存的。所以,只有当一个区域处于激活状态,才会load至内容中,当然,你也可以一次性将他们全部load进内存,这需要有很高的配置。当没有玩家进入地图区域,或者玩家离开地图区域一定时候后,可以将该部分地图数据全部unload以节省内存;所有继承自Worldserver的zone 都可以划分为1-n个镜像,只有处于同一个镜像的玩家和entity才可以进入同一个数据广播池,进行交互;可以配置单一镜像的最大entity容量,玩家在进入世界的时候动态分配镜像;可以根据任务进度指定切换镜像ID;public zone server采用 TCP 协议与客户端进行通信;public zone server采用状态同步(state synchronization)技术,全球统一物体id标识 (Guid);以及highguid(服务端)to lowguid(客户端)标识转换。public zone server 集成了移动速度验证,传送验证,飞行验证,等反外挂手段,能够有效的防止客户端伪造指令包的hack 副本区域服务池(instance server pool) 副本区域服务池是一个可以动态分配副本区域的服务池,当有玩家进入副本时,会从池子中随机分配一个zone给该副本,执行和worldserver类似的初始化工作后,该副本及可以被玩家进入。当一个副本完成后,在一定时间后,该副本被释放,此zone又回到副本池中为空闲状态。
什么是Hql HQL是Hibernate Query Language的缩写
Hibernate独家查询语言,属于面向对象的查询语言,
编写HQL的时候,不需要写数据库表中字段,而是写属性的名称
Hql与sql的区别 HQLSQL类名/属性表名/列名区分大小写,关键字不区分大小写不区分大小写别名别名?,从下标0开始计算位置(hibernate5之后不支持)?,从顺序1开始计算位置:命名参数不支持:命名参数面向对象的查询语言面向结构查询语言 Hql处理返回的结果集 1.返回对象(多个)时,用List集合接收List< Book >
2.返回单个列段,用字符串就可以接受List< String >
3.查两个列段及以上,默认返回的是Object【】,也可返回对象,前提是有对应的构造函数
4.注意map是函数,所以不区分大小写,返回的是map集合
/** * 返回对象(多个) */ @Test public void testList1() { Query query = session.createQuery("from Book"); List<Book> list = query.list(); for (Book b : list) { System.out.println(b); } } /** * 返回单个列段,用字符串就可以接受 */ @Test public void testList2() { Query query = session.createQuery("select b.bookName as ss from Book b"); List<String> list = query.list(); for (String b : list) { System.
Pycharm安装requests库时提示:“提示’pip’ 不是内部或外部命令,也不是可运行的程序 或批处理文件”时如何处理
今天按照老师的方法用cmd的命令pip来安装requests库时,提示了“‘pip’ 不是内部或外部命令,也不是可运行的程序 或批处理文件”
当时想到的就是python的环境变量没有装好,因为之前安装有了解过Java也遇到过这种情况。
百度了下处理方法:
1.进入【此电脑】-【属性】-【高级系统设置】-【系统属性】,点击【环境变量】进入,点击【系统变量】的Path,点击【编辑】进入,(发现自己确实没有配置。
2.点击【新建】按钮,然后点击【浏览】找到自己安装python的路径,找到Scripts文件夹点击【确定】。
4.配置成功后,注意!!!(我一开始刚才的cmd窗口没有关闭,直接又运行了命令,还是没有成功),配置好环境变量后,一定要重新打开cmd窗口运行命令。
5.重新运行后出现进度条样式,然后输入命令【pip list】,如果出现package version样式(如下图)就说明已经成功啦!