用遗传算法进行特征选择

文章目录 一、问题举例二、算法描述1、基于类内类间距离的可分性判据2、遗传算法(Genetic Algorithm)1) 初始化种群2)计算当前种群 M(t)中每条染色体的适应度值 f(m)3)基于适应度值的选择4)交叉5)变异6)重复迭代 3、顺序前进法和顺序后退法 三、结果1、在 sonar 数据集上验证遗传算法2、在 Iris 数据集上验证遗传算法3、顺序前进法和顺序后退法5、对比算法:顺序前进法和顺序后退法 四、总结五、代码 一、问题举例 要求:在Sonar和Iris数据集上进行验证遗传算法特征选择性能 对比算法:顺序前进法和顺序后退法 特征选择由类别可分性判据+搜索算法实现 二、算法描述 1、基于类内类间距离的可分性判据 要进行特征选择,首先要确定选择的准则,也就是如何评价选出的一组特征。确定了评价准则后,特征选择问题就变成从D个特征中选出使准则函数最优的d个特征(d < D)。 Fisher线性判别采用了使样本投影到一维后类内离散度尽可能小,类间离散度尽可能大的准则来确定最佳的投影方向,这其实就是一个直观的类别可分性判据。可以用两类中的任意两两样本之间的距离的平均来代表两个类之间的距离,现在可以将其推导到多类情况。 令 x_k^((i)), x_l^((j)) 分别为 ω_i 类及 ω_i 类中的D维特征向量,δ(x_k((i))+x_l((j)) ) 为这两个向量间的距离,则各类特征向量之间的平均距离为 式中c为类别数,ni为 ωi类中的样本数,nj为 ωj类中的样本数,Pi 、Pj是相应类别的先验概率。 多维空间中两个向量之间有很多种距离度量,在欧式距离情况下有 用 m_i表示第i类样本集的均值向量 用 ??表示所有各类的样本集的总平均向量 将上述式子代入到平均距离的公式得 也可以用下面定义的矩阵写出 Jd(x)的表达式,令 因为要保证类间离散度尽可能大,类内离散度尽可能小,故定义以下距离判据 基于距离的可分性判据定义直观、易于实现,因此比较常用。没有直接考虑 样本的分布情况,很难在理论上建立起它们与分类错误率的联系,而且当两类样 本的分布有重叠时,这些判据不能反映重叠的情况。为了简化计算,采用基于类 内类间距离的可分性判据,且根据公式可知,Jd(x)的值越大,表示特征的可分离性越好. 2、遗传算法(Genetic Algorithm) 遗传算法把候选对象编码为一条染色体(chromesome),在特征选择中,如 果目标是从 D 个特征中选择 d 个,则把所有特征描述为一条由 D 个 0/1 字符组 成的字符串,0 代表该特征没有被选中,1 代表该特征被选中,这个字符串就叫 做染色体,记作 m。显然,要求的是一条有且仅有 d 个 1 的染色体,这样的染色 体共有 ?

void SysTick_Handler(void)系统滴答时钟中断函数

可以作为整个系统的时基!在小调度程序和实时操作系统中可以用作系统的时基。 微控制器的定时器资源一般比较丰富,比如STM32存在8个定时器,为啥还要再提供一个SYSTICK? 原因就是所有基于ARM Cortex_M3内核的控制器都带有SysTick定时器,这样就方便了程序在不同的器件之间的移植。而使用RTOS的第一项工作往往就是将其移植到开发人员的硬件平台上,由于SYSTICK的存在无疑降低了移植的难度。 SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。 要注意的是,当处理器在调试期间被喊停(halt)时,则SysTick定时器亦将暂停运作。 由一下三个寄存器控制: CTRL 寄存器:CTRL 是 SysTick 定时器的控制及状态寄存器 LOAD 寄存器:LOAD 是 SysTick 定时器的重装载数值寄存器 VAL 寄存器:VAL 是 SysTick 定时器的当前数值寄存器 CALIB 寄存器:CALIB 是 SysTick 定时器的校准数值寄存器 3.5版本的库函数与以往的有所区别 不存在stm32f10x_systick.c文件,故原来的一些函数也不存在,比如SysTick_SetReload(u32 reload);SysTick_ITConfig(FunctionalState NewState);等 在3.5版本的库函数中与systick相关的函数只有两个 第一个,SysTick_Config(uint32_t ticks),在core_cm3.h头文件中进行定义的。 第二个,void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource),在misc.c文件中定义的。 SysTick_Config(uint32_t ticks),在core_cm3.h 主要的作用: 1、初始化systick 2、打开systick 3、打开systick的中断并设置优先级 4、返回一个0代表成功或1代表失败 注意: Uint32_t ticks 即为重装值, 这个函数默认使用的时钟源是AHB,即不分频。 要想分频,调用void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource), 但是要注意函数调用的次序,先SysTick_Config(uint32_t ticks), 后SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource)

C语言的getBit,setBit和resetBit位操作函数

C语言getBit, setBit, resetBit程序 使用方便的getBit,setBit,resetBit位操作函数getBit,setBit,resetBitgetBit函数setBit函数resetBit函数 总结 使用方便的getBit,setBit,resetBit 在嵌入式开发过程中,一般采用C语言的编程比较多,但在程序中缺少对位进行操作的函数。所以做了自己的几个函数,可以方便的实现对位的操作。 位操作函数getBit,setBit,resetBit getBit函数 geiBit函数是用来获取每个位的1或者是0. 程序如下: bool getBit(word n, word k) { bool bx; if(((n >> k) & 1) == 1) bx = true; else bx = false; return bx; // return (n>>(k-1)) & 1; // shift n with k - 1 bits then and with 1 } 这里要注意的是一般的计算机采用bool来表示二进制变量。但是这个二进制变量也要占用8个位,即一个字节。用getBit函数取出每个位的0或者是1,然后用bool类型的变量来表示这个变量。 setBit函数 setBit函数是用来设置一个变量的特定的位置1. 程序如下: uint16_t setBit(uint16_t n, int8_t k) { uint16_t nx; nx = 0x1 << k; // set k bit of nx = 0; return n = nx | n; } 这个程序先左移k位,然后用这个第k位的1与原来的结果进行与操作,使特定的位保证是1。

前端页面适应不同分辨率

前端开发要考虑到不同分辨率电脑的页面展示问题,在开发者电脑上的界面在用户电脑上打开可能出现很大变形。 解决方案主要有: 针对不同分辨率用户设置不同的css使用JS/jQuery动态调整使用前端框架 简单介绍一下: 针对不同分辨率用户设置不同的css(不推荐) 即针对不同的分辨率,开发不同的css样式,在界面加载时,先判断用户屏幕分辨率,在应用相应的css 相比较,这种方法最复杂,而且如果系统面向大众,需要作很多不同的css 推荐文章:PC端页面适应不同的分辨率的方法 使用前端框架 针对不同分辨率展示问题,有很多大牛开发了诸多框架,最为知名的即Bootstrap,也是github上最为知名的框架 Bootstrap提供了许多css样式,在标签中应用这些样式后,前端页面即可自动针对不同分辨率调整显示样式。此外,Bootstrap还开发了一些常用前端控件,如轮播、导航栏、进度条等等。 Bootstrap的学习也较为简单。 相比较,这是最一劳永逸的方法,学会后可以很简单的进行前端工程开发,相当省事。Bootstrap(及其他同类前端框架)必定是前端开发的趋势。 使用JS/jQuery动态调整 这种方法只适合于要调整的页面元素较少的情况,如果分辨率改变后,页面中很多元素都有变形,而且页面整体变得混乱,不适合使用此方法。 常用的方法有: 获取屏幕宽度/高度/分辨率,针对各种情况设置样式 var screenw=screen.width; switch (screenw){ case 1920: $('.Hhandle').attr('data-height',343); break; case 1536: $('.Hhandle').attr('data-height',373); break; } 获取屏幕宽度/高度/分辨率,找到其与样式之间的关系 var screenw=screen.width; var setwidth=503.1942591335728-0.0836961379926832*screenw $('.Hhandle').attr('data-height',setwidth);

如何判断随机变量是否服从正态分布

(分布检验问题)假设有n个随机数,检验这些随机数是否由高斯分布产生,方法如下: 1. 计算n个随机变量的平均值u; 2. 对n个随机变量排序,并计算相邻两个数的差dx; 3. 对第2个数到第n个数,计算z[i]=(x[i]-u)/dx; 4.求出max{z[i]},min{z[i]},将区间[min,max]划分n份,统计属于前i个区间的z[j]元素个数,即满足z[j]<=min+((max-min)/n)*i的z[j]个数num[i]; 5. 将min+((max-min)/n)*i)做为横坐标,num[i]作为纵坐标,判断这个n-1个点是否在一条直线上;这样将问题转化为判断n个点是否共线的问题。 参考书: 1.《数学指南--实用数学手册》P78,埃博哈德 蔡德勒 等编, 李文林等译。

【CMD命令学习】使用CMD的copy /b命令合并两个文件,分离两个文件。

问题:使用CMD将两个文件合并为一个文件。 环境:WIN10 最近发现了一个很实用的命令,那就是copy /b。我们看看帮助文档。 其命令格式是copy /b a.xxx [+b.xxx [+...]] c.xxx,[]代表可选。意思是将a.xxx和b.xxx合并为c.xxx。 我们来实践一下:某文件夹下有两张jpg图片(船1.jpg和哈登1.jpg)和一个rar压缩包(哈登1.rar),现在我们将哈登1.jpg与船1.jpg合并。 1.首先WIN+R运行CMD 2.进入到目标文件夹。命令是CD C:\Users\Chengyikang\Pictures\示例 3.使用copy /b命令进行合并。命令是copy /b 船1.jpg+哈登1.jpg 合并后的图片1.jpg 我们用dir命令可以看到,合并后的图片大小是合并前的两张大小之和。并且看不到哈登的图片了。 但是!这样子如果不知道第二个文件从哪个字节开始的,不容易分离开,可能要借助Cmder等工具,太复杂。 我们可以这样实现“分离”,将想要隐藏的文件夹打包压缩,这时候哈登1.rar派上用场了。 1.同样的合并操作。命令是copy /b 船1.jpg+哈登1.rar 合并后的图片2.jpg 我们看到生成了合并后的图片2.jpg。 2.我们将其后缀名改成rar。 打开看看。 哈哈 ,又看到了哈登1.jpg!ヾ(o・ω・)ノ 这个方法简单易学,实现了一定程度上的“隐藏”,“分离”,至于用途大家就自行发挥了( • ̀ω•́ )✧( • ̀ω•́ )✧( • ̀ω•́ )✧。 前段时间这个命令确实派上大用场了,希望对你也有用。喜欢点个赞!

dyn_threshold对物体轮廓提取很有用的一个阈值分割算子

先来看看这个算子的参数选择: dyn_threshold(OrigImage, ThresholdImage : RegionDynThresh : Offset, LightDark : ) ThresholdImage是我们用来作为灰度值参考的另外一幅图像,在实际使用过程中通常都是对原图像OrigImage进行一次平滑处理,然后用平滑处理之后得到的图像作为参考图像。 LightDark是问我们提取亮?暗?还是相似的区域?(当然,这是相对于ThresholdImage) Offset其实是在设定一个比较的区间范围,因为在图像处理这个主观性本来就比较强的领域中“绝对”这个科学名次实在有点太过分,所以什么事情,只要在一个合理的范围内,我们都是可以接受的,而不是死死抓住一个点不放,最后也得不到想要的结果。 dyn_threshold 这个算子就是根据一套灰度值比较规则来选择原图像中那些灰度值符合这个公式的像素点。 令 g_{o} = g_{OrigImage}, g_{t} = g_{ThresholdImage}分别代表原图和参考图中的像素点的灰度值. 我们的做法是把参考图像的灰度值加上(减去)一个Offset,然后去和原图的像素点逐像素对应地进行比较。 下面看Halcon中给出的这些公式: The condition for LightDark = ‘light’ is: g_o >= g_t + Offset 既然选择light,那就代表提取相对参考图来说亮一些的地方,那么自然要选择那些灰度值比g_t + Offset要大的像素点。 For LightDark = ‘dark’ the condition is: g_o <= g_t – Offset 如果要提取的是比参考图要暗一些的区域,那么自然要选择比g_t的灰度值要小的那些像素点,但是这样直接比较的话提取的小区域太多了,并没有很好地提取出相对参考图来说很明显有差别的那部分,所以我们才给定Offset这个参数用来修正。这样给参考图的灰度值一减掉Offset,提取出来的和参考的之间的差距就会很明显。 For LightDark = ‘equal’ it is: g_t - Offset <= g_o <= g_t + Offset 选择equal的意思是选择那些和参考图的差不多的,只要在这个合理的范围内的都算。 Finally, for LightDark = ‘not_equal’ it is:

推荐算法技术架构

本质上技术架构,都是 数据 - 清洗 - 加工 - 算法 - 召回 - 精排 - 过滤 第一种 第二种 

项目进展跟踪方法:

项目进展跟踪方法: 1原则 运作规则: 1、每天早上10:00,硬测将前一天的新增待确认问题在5.9C11硬件质量保障交流群中知会 2、每天早上发出的和UET相关的问题,UET需在当天下午下班前确认完毕,给出是否是问题、涉及组件等信息 3、UET调试时发现的问题需要自提单,并在正式版本发布时写清当前已知缺陷列表;后续硬测发现的问题,若无问题单号,一律按照新增问题提单处理4、UET问题目标日清日结 问题处理要求: TR4A前自身代码缺陷自提单走简易三步单; 自验证其它组件缺陷走标准单; 再详细点 2 每日进展 事务提出时间计划完成时间实际闭环时间责任人状态进展 3 问题跟踪 DTS单号问题描述单板问题类型归属组件责任人跟踪责任人提出时间计划完成时间闭环时间优先级状态定位进展 4 已关闭问题 DTS单号问题描述单板问题类型归属组件责任人跟踪责任人提出时间计划完成时间闭环时间优先级状态定位进展 5 风险跟踪 关键问题&风险提出时间闭环时间状态责任组件责任人跟踪责任人进展 6 关键事务跟踪 序号事务描述状态交付时间责任人进展是否风险

Halcon|读取3D相机点云数据

Halcon|读取3D相机点云数据 最近发现很多小伙伴在使用Halcon处理3D工业相机扫描结果的时候遇到了“如何读取”的问题。一般的3D工业相机储存数据的格式有txt格式、tif格式、csv格式、ply格式、ptx格式、bin格式、obj格式等。 txt格式 读取txt文件生成3D模型一般需要分析txt文件的储存格式,下图是我使用的工业相机储存的部分txt数据: 经过分析,前3列为X、Y、Z坐标,第4列到第6列为每一点的法线坐标nX、nY、nZ,第7列到第9列为灰度值。因此我们采用以下代码重构3D模型: open_file ('data.txt', 'input', XYZ) #打开文件 X :=[] Y :=[] Z :=[] nX :=[] nY :=[] nZ :=[] Gray :=[] fread_line (XYZ, OutLine, IsEOF) #读文件中一行的字符串 tuple_split (OutLine, ' ', Substrings) #根据空格分割一行的字符串 while (IsEOF==0) #将X Y Z nX nY nZ Gray分别存储在不同的元组中 X :=[X,Substrings[0]] Y :=[Y,Substrings[1]] Z :=[Z,Substrings[2]] nX :=[nX,Substrings[3]] nY :=[nY,Substrings[4]] nZ :=[nY,Substrings[5]] Gray :=[Gray,Substrings[6]] fread_line (XYZ, OutLine, IsEOF) tuple_split (OutLine, ' ', Substrings) endwhile close_file (XYZ) #关闭文件 tuple_number (X, NumberX) tuple_number (Y, NumberY) tuple_number (Z, NumberZ) #将字符串转化为数字 gen_object_model_3d_from_points (NumberX, NumberY, NumberZ, ObjectModel3D) #构建3D模型 visualize_object_model_3d (3600, ObjectModel3D, [], [], [], [], [], [], [], PoseOut) #显示3D模型 代码中的IsEOF参数为循环的判断变量,当文件未到末尾时,IsEOF为0;当文件到达末尾时,IsEOF为1。

P问题、NP问题、NPC问题、NP hard问题

图论算法摘要 1. 图的概念 图 一个图(graph) G = ( V , E ) G=(V,E) G=(V,E) 由顶点(vertex)集 V V V 和边(edge)集 E E E 组成。 每一条边就是一个点对 ( a , b ) , a , b ∈ V (a,b),a,b∈V (a,b),a,b∈V。有时候也把边叫做弧(arc)。 有向图 如果点对 ( a , b ) , a , b ∈ V (a,b),a,b∈V (a,b),a,b∈V是有序的,那么图就是有向的(directed)。即 ( a , b ) (a,b) (a,b)和 ( b , a ) (b,a) (b,a)指不同的边。即这条边必须从点a指向点b,而不能反过来。 有向的图称为有向图(digraph)。 顶点 m m m 和 n n n邻接当且仅当 ( m , n ) ∈ E , m , n ∈ V (m,n)∈E,m,n∈V (m,n)∈E,m,n∈V

用户偏好标签

实现步骤 1.建立底层数据 包含,商品表、用户信息表、浏览日志表、加入购物车日志表、订单日志表 2.T+1,针对每天日志数据,将用户打上行为标签 涉及表: 行为权重表、用户行为标签表 标签权重核心计算方法 三 对每个用户偏好的每个标签加总求权重值,对权重值做倒排序,取top N

使用redis 报错Address already in use redis无法启动问题 oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo

报错Address already in use 表示的6379端口被占用 或者报以下错误 60192:C 17 Jan 2019 00:04:58.948 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 60192:C 17 Jan 2019 00:04:58.948 # Redis version=5.0.2, bits=64, commit=00000000, modified=0, pid=60192, just started 60192:C 17 Jan 2019 00:04:58.948 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf 60192:M 17 Jan 2019 00:04:58.949 * Increased maximum number of open files to 10032 (it was originally set to 256).

Qt实现简易计算器

最近没事在学习Qt,做了一个简易计算器的小设计。记录在此,方便大家,也方便自己。 一、整体方案设计 本设计总体可分为两个部分,界面设计部分和内部逻辑部分。下面分别进行讲解。 二、界面设计部分: 界面设计入上图所示一些按钮和一个QLineEdit(用于输入数字和显示结果)和QLabel(用于显示运算表达式)。 本部分主要是采用界面设计师(直接拖拽设计)和代码设计部分。其中代码设计部分主要是为了完成图中所示的布局。具体的代码如下所示: Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); connect(this,&Widget::SendOpe,this,&Widget::RecOpe); connect(this,&Widget::SendNum,this,&Widget::RecNum); setFixedSize(this->width(), this->height()); //禁止改变窗口大小 //设置布局 QVBoxLayout *layout1 = new QVBoxLayout(); layout1->addWidget(ui->label_show_exp); layout1->addWidget(ui->lineEdit) ; QGridLayout *layout = new QGridLayout(); layout->addWidget(ui->pushButton_CE,0,0,1,1); layout->addWidget(ui->pushButton_C,0,1,1,1); layout->addWidget(ui->pushButton_bac,0,2,1,3); layout->addWidget(ui->pushButton_7,1,0,1,1); layout->addWidget(ui->pushButton_8,1,1,1,1); layout->addWidget(ui->pushButton_9,1,2,1,1); layout->addWidget(ui->pushButton_add,1,3,1,1); layout->addWidget(ui->pushButton_lef,1,4,1,1); layout->addWidget(ui->pushButton_4,2,0,1,1); layout->addWidget(ui->pushButton_5,2,1,1,1); layout->addWidget(ui->pushButton_6,2,2,1,1); layout->addWidget(ui->pushButton_sub,2,3,1,1); layout->addWidget(ui->pushButton_rig,2,4,1,1); layout->addWidget(ui->pushButton_1,3,0,1,1); layout->addWidget(ui->pushButton_2,3,1,1,1); layout->addWidget(ui->pushButton_3,3,2,1,1); layout->addWidget(ui->pushButton_mul,3,3,1,1); layout->addWidget(ui->pushButton_0,4,0,1,2); layout->addWidget(ui->pushButton_poi,4,2,1,1); layout->addWidget(ui->pushButton_div,4,3,1,1); layout->addWidget(ui->pushButton_equ,3,4,2,1); layout1->addLayout(layout); setLayout(layout1); setWindowTitle(tr("简易计算器")); //设置程序标题 ui->lineEdit->setText("0"); //初始化 flag = 0; //括号标志 //设置背景,按钮透明等样式 SetSty(); } 代码分析:以上代码主要是完成了界面的布局。基本上外部的垂直布局里面套了个网格布局(网格布局里主要是处于下方的按钮)。 还有SetSty()函数主要是为了突出一些逼格,重新包装了一下整个程序,其实也就是设置了下背景,按钮样式之类。包装之后的界面入下图所示:

Oracle insert all 详解

文章目录 1 概述2 insert 的两种形式2.1 insert first2.2 insert all 3 数据一致性(同时插入)3.1 验证:insert into 数据不一致3.2 验证:insert all 数据一致 1 概述 1. 作用:'正确、高效' 的将 '同一批数据' 插入至 '不同的表' 中 2. 好处 (1) '正确':避免数据差异 (2) '高效':优于写多个 insert into(因为无论插入多少张表,'主表' 只会被读取一次) 3. 场景,若需求:将表 t 中的数据 '同时插入' 至表 t1、t2 若不知晓 insert all 语句,咱可能会使用 insert into 两次 insert into t1 select * from t; insert into t2 select * from t; 问题:在两次 insert 过程中,有可能 t 表的数据发生了改变, 从而导致 t1、t2 '得到的数据不一致'。 解决办法:insert all 2 insert 的两种形式 1.

CSkin界面库窗体设置

CSkin界面库是一款免费的C#界面库,具有小巧免费,拓展性强,容易上手等优点,适合用于中小规模软件的开发。使用这个界面一年多了,但一般最多也只是改改颜色之类的简单应用,官网也只给了简单的例子,并没有说明文档,大部分都得靠自己摸索和实践,于是想简单介绍一下这个界面库。 从官网http://www.cskin.net/下载界面库,解压有两个dll文件,一个是dll文件,一个是net 2.0,一个是net4.0。 导入界面库到工具箱(具体导入方法可以查看:http://bbs.cskin.net/thread-619-1-1.html),引入命名空间,并继承Skin_Color类 using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using CCWin; namespace CSkinDemo { public partial class Form1 : Skin_Color { public Form1() { InitializeComponent(); } } } Skin_Color是实现窗体美化的一个类,类似的类还有Skin_DevExpress,Skin_Mac,Skin_Metro,Skin_VS,这几个类的属性都差不多,因此这里只介绍Skin_Color的几个常用属性。 Skin_Colr界面 (1)BackPalace 质感层背景,设置以后窗口标题栏的背景图也是该背景 (2)BackShade 背景渐变效果开启/关闭 (3)CaptionBackColorBottom 窗口颜色渐变的起点值 (4)CaptionBackColorTop 窗口颜色渐变的终点值 (5)CloseBoxSize 关闭按钮的大小,CSkin界面库可以改变Close按钮的图片,当然也可以改变大小 (6)CloseDownBack,CloseMouseBack,CloseNormalBack CloseDownBack指的是该按钮按下时的背景图,CloseMouseBack指的是鼠标移动到按钮上的背景图,CloseNormalBack是初始时的背景图,最大化按钮和最小化按钮也有这三种状态,不再赘述。 (7) Radius、RoundStyle 这两个属性和设置窗体圆角相关,Radius设置圆角大小,RoundStyle设置圆角样式,当RoundStyle为None时,关闭圆角。 (8)Shadow,ShadowColor,ShadowPalace,ShadowWidth 这几个属性都和阴影相关 Shadow 是否开启阴影 ShadowColor 阴影颜色 ShadowPalace 阴影背景图 ShadowWidth 阴影宽度 简单设置后,效果如下 具体属性设置可以查看工程:https://download.csdn.net/download/sinat_27720649/10920809 注意:CSkin界面库的属性大部分都有中文说明,但是因为笔记本屏幕小或者属性过多,属性说明栏被上方的属性设置栏遮挡了 ,需要自己手动拉伸。

从华为任正非罕见接受外媒采访透漏出来的强大的华为基因

任正非罕见接受外媒采访最后一句话的亮点:“华为不是上市公司,我们不需要漂亮的财报。”、“如果他们不想让华为进入某些市场,我们可以缩小规模。”、“只要我们能生存下去,养活我们的员工,我们就有未来。” 已经年收入超过千亿美元,企业端和个人端产品都是全球差不多第一的位置,依然俯下身子要生存下去,养活自己的员工。这种低调的魅力成为企业的一种精神,是一种发自内心的力量。 纵观当前的另外一些企业与企业老板,拿到一个大项目就沾沾自喜,拿到一笔投资就狂妄不一,还没上市就谋求跑步发展。生存两个字似乎无关紧要,养活员工的目标那也是不屑一顾。眼里全是外在的虚荣和目无一切的傲慢。 很欣赏互联网的快,但不是盲目的快,是准确看到需求急迫满足并验证的效率。有的公司拿到几十亿上百亿的融资,但是快的连内部的巨大的腐败都管理不住,这是对投资的亵渎,是突破了底线的速度追求。 踩着脚步的奔跑就不会绊倒,坚持和韧性才是走到最后的关键。

广东联通打通全球首个5G手机电话

近日,广东联通联合中兴通讯在深圳5G规模测试外场,打通了全球第一个基于3GPP最新协议版本的5G手机外场通话(FirstCall), 率先在5G网络下畅享了微信、视频等精彩应用,对5G商用进程意义重大。 在中央经济工作会议精神鼓舞下,中国联通积极响应国家号召,加快5G建设步伐,以打造极致用户体验为目标,高起点建设5G精品网络,广东联通以实际行动加速推进5G行业发展,迈出了坚实的一步。 本次测试采用了遵循3GPP 2018年9月30日协议版本的核心网、传输承载网、无线网到终端的5G端到端解决方案,现网验证了大规模天线阵列、5G新空口、NSA 双连接模式、FlexE传输技术、全NFV虚拟化核心网等最新关键技术。广东联通全球率先通过无线方式实现了5G手机终端与网络成功对接,加速推动5G终端产业链的成熟。

关于System.InvalidOperationException:“Nullable object must have a value.异常

关于System.InvalidOperationException:“Nullable object must have a value.异常 这个问题是在今天早上遇到了,纠结了很久,反复检查了数据库的设计以及EF中的实体模型是否准确,最后终于找出了解决方案。 首先出现这个问题的原因在于你所要获取的那个对象的某个可以为null的字段被赋值为null。 如上图的People实体中的Id这个字段是可空类型的。 接下来进入赋值阶段。 点击运行,抛出以下异常。 所以如果要避免这种异常的方法是将.Value属性去掉即可。

mixamo 导出的模型没有贴图

任意创建一个文件夹,例如“material", 然后,import settings ->Materials --> Extract Textures -->选择 material 文件夹 ,导出即可 Next select the folder you created.

Vue中的数组赋空值注意事项

在js或者Vue中,给数组赋空值不可以直接赋空值,例如: var list = {a:'12',b:'34'};// 创建一个数组 list = [];// 数组赋空值 否则会在再次赋值的时候报错

个人博客上线啦

个人博客正式上线啦,提升体验,没有烦人的广告。 访问地址: blog.xinhao.info 谢谢大家的支持!

vue使用vant-ui 使用Picker添加多级选择

vue使用vant-ui 使用Picker添加多级选择 <template> <div class="timer"> <van-popup v-model="timeshow" position="top" :overlay="false"> <van-picker :columns="columns" :show-toolbar='true' title='什么时候吃面包' @change="onChange" :visible-item-count='5'/> </van-popup> </div> </template> <script> let h = []; let m=[]; // 添加小时 for (var i = 0; i < 24; i++) { if (i < 10) { h.push("0" + i + "时"); } else { h.push(i + "时"); } } //添加分钟 for (var i = 0; i < 60; i++) { if (i < 10) { m.

eclipse 配置多个tomcat服务器

我们在开发过程中经常需要同时启动多个tomcat服务器,这里讲解一下如何可以在一个eclipse配置多相同的tomcat服务器应用于开发。 开发步骤 步骤一 (1)在tomcat的安装目录下复制我们的tomcat 这两个tomcat都是一个版本,这是解压的路径不同而已。 如果你想安装不同版本的tomcat,入tomcat6或者tomcat7也是一样的,解压路径不同即可。 步骤二 (1)在eclipse的工具栏选择Windows–>Prefernces (2)选择Server–>Runtime Environment,Add添加tomcat (3)Next选择我们的tomcat的安装路径,这里就要跟第一个安装路径不同,选择JRE版本,也可以自定义名称,finish即可完成。 步骤三 (1)在Servers控制台添加tomcat (2)再控制台空白处右键,选择New–>Server 在Server runtime environment记得选择我们新添加的tomcat。Finish即可 这样我们就成功添加两个tomcat服务器了。 步骤四 为什么要添加两个不同的tomcat的路径,而不是新增两个server,因为我们需要配置tomcat的端口号,使用同一个tomcat服务器会造成端口冲突。 (1)修改tomcat的端口号,点击我们Servers控制台的Tomcat 在ports上修改tomcat的端口号,记得修改的三个端口号要与我们第一个配置的端口号不一致。这样启动两个tomcat才不会导致端口冲突的问题。 (2)也可以去tomcat的安装目录的conf文件夹下的server.xml配置文件中修改端口号。记得也是修改3个端口号 这样我们使用不同的tomcat启动多个项目就不会互相影响了。

在同一台服务器上配置多个Tomcat的方法_Tomcat

摘要: 本文讲的是在同一台服务器上配置多个Tomcat的方法_Tomcat , 如果要在一台服务器上配置多个Tomcat,主要就是要避免Tomcat服务器的端口冲突的问题。只需要修改CATALINA_HOME\conf\server.xml中的启动端口和连接端口就OK了! 下面我们把配置的详细过程写在下面,以供参考 如果要在一台服务器上配置多个Tomcat,主要就是要避免Tomcat服务器的端口冲突的问题。只需要修改CATALINA_HOME\conf\server.xml中的启动端口和连接端口就OK了! 下面我们把配置的详细过程写在下面,以供参考:(此例以配置三个Tomcat为例) 下载apache-tomcat-7.0.63,下载地址:http://tomcat.apache.org/download-70.cgi下载下来的文件为apache-tomcat-7.0.63.zip. 解压该压缩包到D:/div/目录下。 修改解压文件夹名字为:tomcat7-8080 在D:/div/目录下创建该文件夹的两个副本,分别更名为:tomcat7-8081、tomcat7-8082 添加环境变量:右键单击我的电脑->选择属性->选择高级->选择环境变量:添加系统变量: CATALINA_HOME_8080,其值为:D:\div\tomcat7-8080; CATALINA_HOME_8081,其值为:D:\div\tomcat7-8081; CATALINA_HOME_8082,其值为:D:\div\tomcat7-8082; 修改启动端口和关闭端口: 进入D:\div\tomcat7-8081\conf\目录,打开server.xml文件,修改下面两个地方: (1) 修改这个port=”8006”,原来默认的为:8005,使得它的关闭端口和另一个关闭端口不发生冲突。 (2) 修改port=”8081”,原来默认的为“8080”,使得它的连接端口和另一个不冲突。 (3) 修改这个port=”8010”,原来默认的为:8009,AJP 1.3 Connector定义的地方。 修改startup.bat和catalina.bat文件内容: (1) 打开D:\div\tomcat7-8081\bin\startup.bat文件,把其中所有CATALINA_HOME替换为CATALINA_HOME_8081。 (2) 打开D:\div\tomcat7-8081\bin\catalina.bat文件,把其中所有CATALINA_HOME替换为CATALINA_HOME_8081。 tomcat7-8082配置方法跟配置tomcat7-8081步骤一样的。 8.启动Tomcat,在命令行下分别进入三个不同的Tomcat安装目录下,执行startup.bat,分别启动三个Tomcat。然后在浏览器中输入: http://localhost:8080 http://localhost:8081 http://localhost:8082 至此,我们已经在一台服务器上配置了三个Tomcat。 原文链接:http://www.cnblogs.com/linjiqin/p/5488461.html 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持云栖社区。 以上是在同一台服务器上配置多个Tomcat的方法_Tomcat 的全部内容,在云栖社区的博客、问答、云栖号、人物、课程等栏目也有在同一台服务器上配置多个Tomcat的方法_Tomcat 的相关内容,欢迎继续使用右上角搜索按钮进行搜索idea配置tomcat服务器、tomcat 服务器配置、tomcat配置图片服务器、如何配置tomcat服务器、java配置tomcat服务器,以便于您获取更多的相关知识。

PHP yield大文件读取 与 数据库大数据量读取

PHP yield大文件读取 与 数据库大数据量读取 yield php5.6版本才有的函数,作用是 实现 生成器,作用的在读取文件的时候,可以一行一行的读取 简单的说可以理解为 php版本的非缓冲查询,意思即是 把数据一行行 读取到php运行内存,并非一次性读取到php运行内存,众所周知,php有很多内置函数,可以帮助我们对数据进行加工操作,因为数据都在内存里面,所以能操作,但是php的运行内存是有极限,默认128M。这里不描述 对文件的读取。 数据库结构: php链接mysql版本的 yield 实现方式--------非缓冲查询,如图: 注意:因为非缓冲查询是 会长时间连接数据库的,有可能会造成慢查询、锁表之类的情况,比较耗mysql资源 相对非缓冲查询就是 缓冲查询: 如果用缓存查询,php内存就会直接爆了,出现内存不足的情况 以下附上php 实现 yield 链接 mysql 几种方法: 1) <?php $link = mysqli_connect('localhost','root','','advertising'); if( $result1 = mysqli_query($link, 'SELECT * FROM `test`',MYSQLI_USE_RESULT) ) { $result = $result1; // unset($result1); // mysqli_close($link); //如果这里切断 mysql 链接 将无法获取 数据,原因是加了MYSQLI_USE_RESULT while ( $res = mysqli_fetch_assoc($result1) ){ echo $res['a'] . PHP_EOL; $i++; if( $i ==1000 ){ exit; } } } ?

linux上运行php目录不可写问题(无权限)

linux上运行php目录不可写问题(无权限) 原因是 项目当前用户并不是 php当前运行用户 只要把项目下的文件夹以及文件 改变用户组跟用户即可 修改php 的用户组 注意这里的路径是我本机的路径,请自行修改

Ubuntu18.04/16.04+ Tensorflow1.8 +anaconda安装总结

Ubuntu18.04/16.04+ Tensorflow1.8 +anaconda安装总结 主要参考网址: 1.https://blog.csdn.net/Aiolia86/article/details/80342240 2.https://blog.csdn.net/weixin_40920290/article/details/80462734#3cudnn70 Ubuntu18.04发行已经有一段时间了,正好最近Tensorflow也发布了1.8版本,于是决定两个一起装上,以下是安装总结,时间证明该教程适用于ubuntu16.04与18.04,。 大致可以分为5个步骤 确认当前软件和硬件环境、版本 更新显卡驱动,软件版本准备 CUDA 9.0 ToolKit安装 cuDNN7.1.3 for CUDA9.0安装 TensorFlow GPU 安装 Test it! 1.确认硬件软件环境、版本 系统版本,Ubuntu18.04 自然没什么好说的, 终端输入指令查看ubuntu信息 sudolsb_release-a 得到以下输出结果: No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 18.04.5 LTS Release: 18.04 Codename: xenial GCC和G++ 版本,18.04的ubuntu默认的是7.0,同时也有附带安装6.0,不过我们这次安装需要更低版本的GCC以及G++ 下面两行命令查看gcc和g++版本号: gcc --version g++ --version 我选择采用的是4.8版本gcc和g++,后面给出降级方法。 英伟达显卡驱动版本, 使用nvidia-smi 可以得到相关信息,我使用的是GTX960显卡,驱动使用384.130版本。 Python 版本, python2 –version 和 python3 –version, 应该对应2.7+ 和 3.6+版本了都,默认较新版本,可以忽略。 2.更新显卡驱动,软件版本准备 主要是更新显卡驱动,以及降级默认GCC/G++版本. 如果是已经装过NVIDIA显卡驱动,通过以下指令升级 sudo add-apt-repository ppa:graphics-drivers/ppa

嵌入式Linux开发常用C语言标准库函数

推荐两个网站: http://www.cplusplus.com/ 各大语言基础入门必备网站 菜鸟教程:http://www.runoob.com/ 标准输入/输出类函数 scanf() http://www.runoob.com/cprogramming/c-function-scanf.html printf() http://www.runoob.com/cprogramming/c-function-printf.html putchar() http://www.runoob.com/cprogramming/c-function-putchar.html getchar() http://www.runoob.com/cprogramming/c-function-getchar.html putc() http://www.runoob.com/cprogramming/c-function-putc.html getc() http://www.runoob.com/cprogramming/c-function-getc.html puts() http://www.runoob.com/cprogramming/c-function-puts.html ungetc() http://www.runoob.com/cprogramming/c-function-ungetc.html 字符处理及转换函数 sdigit() http://www.runoob.com/cprogramming/c-function-isdigit.html sprintf() http://www.cplusplus.com/reference/cstdio/sprintf/ strncat() http://www.runoob.com/cprogramming/c-function-strncat.html strlen() http://www.runoob.com/cprogramming/c-function-strlen.html strchr() http://www.runoob.com/cprogramming/c-function-strchr.html strstr() http://www.runoob.com/cprogramming/c-function-strstr.html memset() http://www.runoob.com/cprogramming/c-function-memset.html memmove() http://www.runoob.com/cprogramming/c-function-memmove.html memcpy() http://www.runoob.com/cprogramming/c-function-memcpy.html memcmp() http://www.runoob.com/cprogramming/c-function-memcmp.html

h3lix 越狱后 Cydia 不能上网的修复

使用 h3lix 越狱 10.3.3 的 iPhone5,进入 Cydia 不能联网 解决方法:打开 Cydia,进入已安装列表,点击 Cydia Installer 卸载,然后看到桌面上就没有 Cydia 的图标了 然后重启手机,打开 h3lix 重新越狱,会自动重装 Cydia,打开 Cydia 即可上网。不过这个方法只能适用于 h3lix,通用的方法可以参考 Cydia 不能上网的终极解决方法 原文地址:https://www.exchen.net/ios-hacker-h3lix-%e8%b6%8a%e7%8b%b1%e5%90%8e-cydia-%e4%b8%8d%e8%83%bd%e4%b8%8a%e7%bd%91%e7%9a%84%e4%bf%ae%e5%a4%8d.html

.Net之程序保护(.NET Reactor)

欢迎加入BIM行业开发交流1群 群号:711844216 一、背景 作为开发人员,自己辛苦在.net框架下写的dll或者exe文件,不想被别人通过反编译工具轻松查看。那么我们就需要对自己写的代码进行保护。在笔者经过大量的搜索与尝试后,发现一款不错的程序保护工具.NET Reactor。如其名字所示,这是一款针对.net程序进行保护的专门工具,因为专业,所以强大。 下载地址:https://www.jb51.net/softs/547521.html 接下来我们看下它的基本功能: 二、.NET Reactor功能介绍 主要功能如下: 源码混淆处理字符串加密NET Reactor强大的许可授权管理功能NET Reactor可以为您的软件创建试用版设置过期日期为软件限制一个安装后的可用天数使用次数限制(如将软件作为一种服务) 如果涉及到软件本身的保护,我们可以采用给软件设置使用次数或者期限,对于dll保护我们可以对其进行混淆和字符串加密处理。 三、使用方法 首先,我们需要对Quick Settings 里面的东西有个基本认识 NecroBit:把程序集转为非托管代码;Native Exe File:生成本机 Exe 文件;Anti ILDASM:反编译;Obfuscation:混淆;Create Mapping File:创建地图文件;Anti Tampering:防篡改;String Encryption:加密字符;Compress & Encrypt Resources:压缩并加密资源;Control FlowObfuscation:混淆控制流。 第一步:通过Open找到自己需要加密的dll/exe,然后打开 第二步:对加密进行设置 对于dll或者exe加密,笔者这里推荐勾选 Anti ILDASMObfuscationString Encryption 这三个选项。因为这三个选项基本上能够较好地对代码进行较好的保护了,多选了可能会导致dll/exe不能正常加载或运行。 第三步:点击左下角的Protect就可以了。等待一会儿,DSOffice-Successfully Protected! 接下来我们对比一下结果。这里我们用ILSpy反编译工具查看保护前,和保护后的情况。 保护前 保护后 通过对比我们可以看到 类名,方法名,属性名大部分都不能正常显示代码已经不能再被查看 是不是很神奇,大家动手试试吧 四、注意事项 在进行加密设置时,并不是勾选的越多越好,因为勾选多了容易造成dll\exe不能正常加载或运行;如果在open文件后,出现Can’t load assembly这种情况 那么找到LibG.Interface.dll这个文件,然后添加到这里的Addtional Files,即可。 加密方式有很多,本文介绍这种方式,用以抛砖引玉,大家可以自己多多探索。 微信搜索“工程人的编程课堂” 获得行业资讯,以及更多编程干货

org.apache.http不能引用的问题,解决方式

类里提示爆红 import org.apache.http.Header; import org.apache.http.HeaderElement; import org.apache.http.HttpEntity; import org.apache.http.HttpRequest; import org.apache.http.HttpRequestInterceptor; import org.apache.http.HttpResponse; import org.apache.http.HttpResponseInterceptor; import org.apache.http.HttpVersion; 有下面的错误提示 报错: Error:(19, 23) 错误: 程序包org.apache.http不存在 Error:(20, 23) 错误: 程序包org.apache.http不存在 Error:(21, 23) 错误: 程序包org.apache.http不存在 Error:(22, 30) 错误: 程序包org.apache.http.client不存在 Error:(23, 38) 错误: 程序包org.apache.http.client.methods不存在 Error:(24, 35) 错误: 程序包org.apache.http.impl.client不存在 Error:(175, 9) 错误: 找不到符号 符号: 类 HttpClient 位置: 类 SimpleWikiHelper Error:(175, 33) 错误: 找不到符号 符号: 类 DefaultHttpClient 位置: 类 SimpleWikiHelper Error:(176, 9) 错误: 找不到符号 符号: 类 HttpGet 位置: 类 SimpleWikiHelper Error:(176, 31) 错误: 找不到符号 符号: 类 HttpGet 位置: 类 SimpleWikiHelper Error:(180, 13) 错误: 找不到符号 符号: 类 HttpResponse 位置: 类 SimpleWikiHelper Error:(183, 13) 错误: 找不到符号 符号: 类 StatusLine 位置: 类 SimpleWikiHelper Error:(190, 13) 错误: 找不到符号 符号: 类 HttpEntity 位置: 类 SimpleWikiHelper 解决方法:

汇编语言-(王爽)-学习笔记(第13章 int指令)

int指令格式:int n,n为中断类型码,功能:引发中断过程。cpu执行int n指令,相当于引发n号的中断。过程如下: (1)取中断类型码 (2)标志寄存器入栈,TF,IF置零。 (2)cs,ip入栈。 (4) ip=(n*4),cs=(n*4+2); bios,dos提供的中断历程: 在系统板的ROM中存放着BIOS(基本输入输出系统),BIOS主要功能: (1)检测硬件系统,初始化程序 (2)外部中断和内部中断的中断例程。 (3)对其他硬件设备进行I/O设备操作的中断例程。 (4)其他和硬件相关的中断例程。 DOS 操作系统也提供了中断例程,操作系统向程序员提供的。 所以,BIOS和DOS的中断例程如何安装在内存? 开机后,cpu上电后,初始化(CS)=0FFFFH,(IP)=0,自动从FFFF:0处执行程序。FFFF:0处有一条跳转指令,CPU执行该指令后,转去执行BIOS中的硬件系统检测和初始化程序。初始化程序建立BIOS所支持的中断向量(将BIOS提供的中断例程的入口地址填在中断向量表中)注意:对于BIOS所提供的中断例程只需要将入口地址登记在中断向量表中,因为他们固化在ROM中,一直在内存中。硬件系统检测和初始化完成后,调用int 19h进行操作系统的引导,将计算机交给操作系统控制。DOS启动后,安装所提供的中断例程,建立中断向量表。

汇编语言-王爽(学习笔记)-12章 中断

第12章:内中断 中断:CPU在执行当前正在执行的指令后,检测到从CPU内部或者外部产生的信息,便立即执行收到的信息。用来处理中断信息的程序是中断处理程序。 CPU收到中断信息后,要知道中断信息的来源(CS,IP值)。中断来源由中断类型码标识。中断类型码为一个字节的数据,所以可以有256种中断信息来源。CPU由8位的中断类型码,在中断向量表中查找,找到中断处理函数的入口地址(CS,IP)。中断向量表指定从内存地址0开始,256*4=1024单元(0000:0000~0000:03ffh)的内容是中断向量表。 CPU在以下情况产生中断: (1)除法错误,比如,执行div指令产生除法溢出。:中断类型码:0 (2)单步执行:中断类型码:1 (3)执行into指令:中断类型码:4 (4)执行int指令。:指令格式为int n,n为字节型立即数,提供给CPU的中断类型码。 / 中断过程: 使用中断类型码,在中断向量表中找到中断处理程序的入口,设置CS:IP。这工作由CPU硬件自动完成。 8086CPU收到中断信息后: (1)取得中断类型码N (2)pushf (3)TF=0,IF=0 (4)push cs (5)push ip (6)ip=(N*4),CS=(N*4+2) 以上CPU硬件自动完成,完成最后一步后,CPU执行由程序员编写的中断处理程序。 中断处理程序编写: (1)保存用到的寄存器(2)处理中断(3)回复寄存器(4)iret指令返回。 iret<=>pop ip pop cs popf 编写0中断处理函数(实验12) CODES SEGMENT START: ;将中断处理函数放入安全的内存区 mov ax,cs mov ds,ax mov ax,offset d0 mov si,ax mov ax,0 mov es,ax mov di,200h mov cx,offset d0end - offset d0 cld rep movsb d0:;中断处理函数 jmp short d0start db "overflow!" d0start:;中断处理函数,将字符串送进显存 mov ax,cs mov ds,ax mov si,202h mov ax,0b800h mov es,ax mov di,12*160+36*2 mov cx,9 s: mov al,[si] mov es:[di],al inc si add di,2 loop s mov ax,4c00h int 21h d0end: nop CODES ENDS END START 单步中断:执行一条语句后,进入中断,为实现单步跟踪提供机制。

【Window 硬件】检测哪个程序占用了串口

一、常见提问 如何解决串口(COM)被占用问题 电脑串口号被占用,如何清除 解决串口(COM)被占用问题 我的电脑显示串口被占用,什么原因? 串口端口被占用的解决方法 串口被占用怎么办 window下,怎么查看串口被哪个进程占用,有什么方法或者软件可以协助查看吗? 串口不知被什么程序占用,有谁能帮我找出来吗 如何使用被其它程序占用的串口? 怎样查串口被个程序占用 如何清除Win7中被占用的COM口 串口 二、串口常见占用统计 自己的软件存在BUG没有退出,可以在任务管理器中查看,修复自身软件bug;别的软件开机优先占用,此时需要找到占用串口的程序,卸载程序或删除;USB转串口设备在使用过程热插拔,此时需要查看隐藏的串口,删除、重启计算机。莫名奇妙的Windows软件、硬件占用如:mstsc.exe、svchost.exe、控制面板-电话/调制解调选择-调制解调器、声卡等,这些占用情况,关闭或禁用基本能够解决占用情况,至于是怎么导致的,有可能是由于个人操作、硬件驱动、系统版本等原因导致。 三、查看串口号是否正在使用中 【Win+R】-运行-regedit 计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\COM Name Arbiter 3.1ComDB二进制值说明 ComDB为二进制数据,表示相应串口是否在使用状态。ComDB的数据规则为,COMn 在ComDB数据数值的使用标识为从左到有,第( (n-1)/8+1)列的1<<( (n-1) mode 8+1)位 。0标识无此串口,1标识此串口正在使用。 每两位16进制数据为1列,m范围[0,31]: 第m+1列的第1位标识COM[m*8+1]的使用状态;第m+1列的第2位标识COM[m*8+2]的使用状态;第m+1列的第3位标识COM[m*8+3]的使用状态;第m+1列的第4位标识COM[m*8+4]的使用状态;第m+1列的第5位标识COM[m*8+5]的使用状态;第m+1列的第6位标识COM[m*8+6]的使用状态;第m+1列的第7位标识COM[m*8+7]的使用状态;第m+1列的第8位标识COM[m*8+8]的使用状态。 例:如下图,第30+1=31列数据为0x80,则标识COM [30*8+8]=COM248的串口号为正在使用状态。 3.2重新分配串口号 删除ComDB项,计算机会重建此字段,意味着重新分配所有串口号,如果没有生效可尝试重启计算机。 四、查看隐藏的串口设备 设备管理器中看不到此串口号,但又不能将其他串口设置为此串口号;一些USB设备热插拔后自动分配了更高的串口号;这些都是隐藏串口导致的,找到他们并删除,USB尽量避免热插拔。 4.1设置显示硬件设备状态 set devmgr_show_nonpresent_devices=1 4.2显示隐藏的设备 devmgmt.msc 4.3删除隐藏占用的串口设备 五使用DOS命令查看串口运行状态 Mode 六、查找占用串口的程序 6.1准备好串口工具 如:CEIWEI CommMonitor10.0.1.18011.rar 6.2截获占用串口的程序PID 安装好后监控所有串口,使用对应串口连接的下位机的功能,如“上电”、“断电”或“单片机自定义的弹片触发”等一切可能的功能,往上位机推送数据,此时监控工具会截获下位机往上位机推送的数据并显示在数据区,其中就包括了占用此串口程序进程的PID。 6.3根据PID找到占用串口的程序 任务栏【右键】-任务管理器-详细信息,根据监控工具所示的PID在任务管理器中可以找到对应占用此串口程序的名称。 七、强制释放占用中的串口 7.1方式一、在任务管理器中结束占用串口的程序 任务栏【右键】-任务管理器-详细信息 7.2方式二、先禁用后启用串口设备 计算机【右键】-管理-计算机管理(本地)-系统工具-设备管理器-端口(COM和LPT)-通讯端口【右键】-禁用。 计算机【右键】-管理-计算机管理(本地)-系统工具-设备管理器-端口(COM和LPT)-通讯端口【右键】-启用。 7.3方式三、重启计算机

EventEmitter事件通信(发布订阅)

基于框架(angular,react,vue等)开发的项目都有合适的状态管理库,一般也很少使用eventEmitter,那么一些传统的或者遗留的基于 jQuery + template 的项目如何处理通信问题呢? 解决方案: 发布订阅(EventEmitter事件通信)callback(传递回调函数) 这里简要实现一下EventEmitter class EventEmitter { // 存储所有事件的监听器 es = {}; // 事件订阅 on(eventName, cb, once = false) { if (!this.es[eventName]) { this.es[eventName] = []; } this.es[eventName].push({ cb, once, }); } // 仅订阅一次 once(eventName, cb) { this.on(eventName, cb, true); } // 派发事件,通知订阅者 emit(eventName, ...params) { const listeners = this.es[eventName] || []; let l = listeners.length; for (let i = 0; i < l; i++) { const { cb, once } = listeners[i]; cb.

Spring MVC中的四种提交方式 GET、POST、PUT和DELETE

1.REST风格 具体说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作: GET用来获取资源; POST用来新建资源; PUT用来更新资源; DELETE 用来删除资源。 2.配置文件 由于浏览器只支持POST和GET方法,因此需要使用_method隐藏字段通知Spring这是一个PUT/DELETE请求。 为此,Spring3.0增加了一个过滤器,可以将这些请求转换为标准的http方法,使得支持GET、POST、PUT与DELETE请求,该过滤器是HiddenHttpMethodFilter。 因此,我们需要在web.xml文件中配置此过滤器。 <!-- 过滤器 转化提交方式 --> <filter> <filter-name>hiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>hiddenHttpMethodFilter</filter-name> <servlet-name>DispatcherServlet</servlet-name> </filter-mapping> 前后台代码 完成配置后,就可以在对应页面使用我们的的四种提交方式进行前后台数据的交互了。 前台提交数据: <!-- 获得get --> <form action="stuManager/${stu.stuNo }.action" method="get"> <input type="submit" value="查看"> </form> <!-- 添加post --> <form action="${ctxPath}/stuManager.action" method="post"> <input type="submit" value="添加"> </form> <!-- 修改put --> <form action="${ctxPath}/stuManager.action" method="post"> <input type="hidden" name="_method" value="put"/> <input type="submit" value="修改"> </form> <!-- 删除delete --> <form action="stuManager/${stu.stuNo }.action" method="post"> <input type="

如何快速将多个文件夹下内容合并到一个文件夹下

在需要合并的文件夹路径下新建一个文件夹和tt文件,命名看自己习惯 我命名了一个all的文件夹和c名称的文件 打开c.txt,输入如下内容: for /f "delims=" %%p in ('dir /b/ad') do copy %%p\*.* e:\tt\all\ pause 然后保存该文件,我的文件在E盘tt文件夹下,所以根据自己的请款去改代码。 重命名c.txt文件为c.bat文件 双击运行c.bat即可 进入tt文件夹中查看,里面显示当前目录文件夹中所有的文件.

vue+node express生成器 使用socket.io (websocket)

1.客户端(前端) Index.html引入服务 socket脚本 <script src='https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js'></script> 然后 我的是点击连接websockt handleClick(){ var socket=io("ws://192.168.1.80:3000"); socket.on('chat message', function(msg){ console.log(msg) }) } 服务端先安装 npm install --save socket.io APP.js 不用管 现在是为websocket开服务 服务端 在bin目录下www里面 //添加的socket代码 var io = require('socket.io').listen(server); io.on('connection', function(socket){ console.log('a user connected234'); socket.on('disconnect', function(){ console.log('user disconnected'); }); }); 以下是我全部的www代码 #!/usr/bin/env node /** * Module dependencies. */ var app = require('../app'); var debug = require('debug')('myapp:server'); var http = require('http'); /** * Get port from environment and store in Express.

Python抢票(Windows版本)下载不到requirements.txt

其他系统一样就把txt文件下载本地 进行执行 1.打开cmd窗口 输入:python -m pip install --upgrade pip 更新pip最新版本 2.依赖库进行安装 https://github.com/testerSunshine/12306/blob/master/requirements.txt 进入该连接把requirements.txt文件下载到D盘目录下执行:pip install -r D:\requirements.txt 3.去GitHub把项目下载下来https://github.com/testerSunshine/12306 4.修改项目下>>>config>>>ticket_config.yaml文件 5.修改如图: 6.可以开始抢票了 cmd运行多半失败!建议使用PyCharm运行参考https://blog.csdn.net/yuell102/article/details/86236375 7.如果遇到其他问题 ImportError:No module named yaml参考https://blog.csdn.net/yuell102/article/details/86236375 乱码参考https://blog.csdn.net/yuell102/article/details/86241238

vue项目使用express+socket.io 报错 Invalid Host/origin Header

写另一个前后端分离的websoket 项目 遇到个坑。。。 目测是 webpack DevServer 没有启动 因为 然后 阻止了websoket的连接 然后导致此错误 解决方案:找到webpack 里面的DevServer 设置为true 具体设置看:http://webpack.wuhaolin.cn/1入门/1-6使用DevServer.html

mysql 5.6以下 数据库开启远程访问

版权声明:本文为博主原创,转载时请带本文原链。原文地址: https://blog.csdn.net/qq_36735629/article/details/85992901 建项目难免要配一套环境,然后开启数据库远程访问的权限用以管理线上数据,多搞几次后还是发现搬砖才是王道,所以记录整个流程以便后面搬砖方便 1、 查看3306端口是否开发 1.)firewall-cmd --list-ports 2.)没有就开启 firewall-cmd --zone=public --add-port=3306/tcp --permanen 3.)然后重启防火墙 firewall-cmd --reload 2、连接服务器进入MySQL查看可登陆user和可登陆host 1.)mysql -u root -p 2.)use mysql; select host,user from user; 获取 mysql库中的user表记录了MySQL的用户信息 user指可登陆的用户名;host指可登陆的主机名,也可以是IP; 3.1、添加远程登录用户名和主机(改表法) 1.)添加用户 insert into user (host,user,password,select_priv) values ('125.95.74.168','qingfeng',password('XT9qD9plmVncGUix'),'Y'); select_priv为查看权限,根据自己的需求已可以添加其他权限(Insert_priv,Update_priv,Delete_priv,Create_priv等) 2.)刷新权限表 flush privileges; select host,user,password,select_priv from user; 可以看到我们已经添加上user为qingfeng 访问ip 为125.95.74.168 的用户(现在ip符合要求的用户就能远程登录了)

深入理解printf函数的实现

先看glibc中printf函数的实现源码: ​#include <ansidecl.h> #include <stdarg.h> #include <stdio.h> /* Write formatted output to stdout from the format string FORMAT. */ /* VARARGS1 */ int printf(const char *format,...) { va_list arg; int done; va_start(arg, format); done = vprintf(format, arg); va_end(arg); return done; } ​ printf函数是通过vprintf函数实现的,我们追踪一下vprintf函数 #include <ansidecl.h> #include <stdarg.h> #undef __OPTIMIZE__ /* Avoid inline `vprintf' function. */ #include <stdio.h> #undef vprintf /* Write formatted output to stdout according to the format string FORMAT, using the argument list in ARG.

微信小程序地图(map)组件点击(tap)获取经纬度

微信小程序中使用地图(map)组件,通过点击(tap)获取经纬度,按照官方的回应,暂时是没法做到的,从地图组件API多有残缺判断,怀疑是个实习生干的... 做个变通,适用性有限,请大家参考。基本思路就是在地图上铺满一层marker,从而通过点击marker获得经纬度。 <map id="map" longitude="102.324520" latitude="40.099994" scale="4" bindcontroltap="controltap" polygons="{{polygons}}" bindregionchange="regionchange" markers="{{markers}}" bindmarkertap="markertap" show-location style="width: 100%; height: 700px;"></map> const app = getApp() const markersize = 30 function range(start, edge, step) { for (var ret = []; (edge - start) * step > 0; start += step) { ret.push(start); } return ret; } function markers(northeast, southwest, scale, width, height) { const markerslng = (northeast.longitude - southwest.longitude) * markersize / width const markerslat = (northeast.

汇编语言-王爽(学习笔记)-5-8章

5章: 1.loop指令:loop实现循环功能,cx存放循环次数。 cpu执行loop时,进行如下操作:cx=cx-1;判断cx是否为零,cx不为0,则转至标号处执行程序,cx为0则向下顺序执行。 格式: { mov cx,循环次数 标号: 循环的程序段 loop 标号 } 2 汇编源程序中,数字不能以字母开头。要在前面加0.如 mov ax,ffffh;错误 mov ax,0ffffh;正确,在字母前加0 3一段安全的空间: 注意:我们在纯DOS(实模式)下,可以不理会DOS,直接用汇编操作真实的硬件,因为运行在CPU实模式下的DOS没有能力对硬件系统做全面的检查。但是在Windows,Unix这些运行于CPU保护模式下的操作系统中,不理会操作系统而直接用汇编操作硬件是不可能的。 当直接向一段内存中写入内容时,这段内存不应该存放其他内存的数据或代码,dos方式,一般0:200·~0:2ff空间是空闲的,可以直接写入. 实验【bx】和loop的使用: 实验4:向内存0:200~0:23f依次传入数据0~63(3fh) assume cs:code code segment mov ax,0020h; mov ds,ax;设置(ds)=(0020h) mov bl,0 mov cx,40h;设置循环40h次 s: mov [bx],bx inc bx loop s mov ax,4c00h int 21h code ends end 6章: end可以通知程序的入口。如:标号......end 标号;标号处为程序的入口。 哪一条指令是程序的第一条指令,由可执行文件中的描述信息指明。可执行文件由描述信息和程序组成,程序源自于源程序中的汇编指令和数据。end start指明入口地址,存储在可执行文件描述信息中。 程序框架: ASSUME CS:CODE CODE SEGMENT ....... ...... START: CODE ENDS;代码段结束 END START ;程序结束 6.3 将数据,代码,栈,放入不同的段中

Vue将汉字转为拼音,取出首字母

效果图: .ts import HanziToPinyin from "../../hanziToPinyin"; export default class Message extends Vue { mounted() { let hanZi = "你好吗"; console.log("输出首字母"+HanziToPinyin.instance.initialTreatment(hanZi)); } } hanziToPinyin.ts import Vue from "vue"; export class HanziToPinyin extends Vue { public PinYin = { a: "\u554a\u963f\u9515", ai: "\u57c3\u6328\u54ce\u5509\u54c0\u7691\u764c\u853c\u77ee\u827e\u788d\u7231\u9698\u8bf6\u6371\u55f3\u55cc\u5ad2\u7477\u66a7\u7839\u953f\u972d", an: "\u978d\u6c28\u5b89\u4ffa\u6309\u6697\u5cb8\u80fa\u6848\u8c19\u57ef\u63de\u72b4\u5eb5\u6849\u94f5\u9e4c\u9878\u9eef", ang: "\u80ae\u6602\u76ce", ao: "\u51f9\u6556\u71ac\u7ff1\u8884\u50b2\u5965\u61ca\u6fb3\u5773\u62d7\u55f7\u5662\u5c99\u5ed2\u9068\u5aaa\u9a9c\u8071\u87af\u93ca\u9ccc\u93d6", ba: "\u82ad\u634c\u6252\u53ed\u5427\u7b06\u516b\u75a4\u5df4\u62d4\u8dcb\u9776\u628a\u8019\u575d\u9738\u7f62\u7238\u8307\u83dd\u8406\u636d\u5c9c\u705e\u6777\u94af\u7c91\u9c85\u9b43", bai: "\u767d\u67cf\u767e\u6446\u4f70\u8d25\u62dc\u7a17\u859c\u63b0\u97b4", ban: "\u6591\u73ed\u642c\u6273\u822c\u9881\u677f\u7248\u626e\u62cc\u4f34\u74e3\u534a\u529e\u7eca\u962a\u5742\u8c73\u94a3\u7622\u764d\u8228", bang: "\u90a6\u5e2e\u6886\u699c\u8180\u7ed1\u68d2\u78c5\u868c\u9551\u508d\u8c24\u84a1\u8783", bao: "\u82de\u80de\u5305\u8912\u96f9\u4fdd\u5821\u9971\u5b9d\u62b1\u62a5\u66b4\u8c79\u9c8d\u7206\u52f9\u8446\u5b80\u5b62\u7172\u9e28\u8913\u8db5\u9f85", bo: "\u5265\u8584\u73bb\u83e0\u64ad\u62e8\u94b5\u6ce2\u535a\u52c3\u640f\u94c2\u7b94\u4f2f\u5e1b\u8236\u8116\u818a\u6e24\u6cca\u9a73\u4eb3\u8543\u5575\u997d\u6a97\u64d8\u7934\u94b9\u9e41\u7c38\u8ddb", bei: "\u676f\u7891\u60b2\u5351\u5317\u8f88\u80cc\u8d1d\u94a1\u500d\u72c8\u5907\u60eb\u7119\u88ab\u5b5b\u9642\u90b6\u57e4\u84d3\u5457\u602b\u6096\u789a\u9e4e\u8919\u943e", ben: "\u5954\u82ef\u672c\u7b28\u755a\u574c\u951b", beng: "\u5d29\u7ef7\u752d\u6cf5\u8e66\u8ff8\u552a\u5623\u750f", bi: "\u903c\u9f3b\u6bd4\u9119\u7b14\u5f7c\u78a7\u84d6\u853d\u6bd5\u6bd9\u6bd6\u5e01\u5e87\u75f9\u95ed\u655d\u5f0a\u5fc5\u8f9f\u58c1\u81c2\u907f\u965b\u5315\u4ef3\u4ffe\u8298\u835c\u8378\u5421\u54d4\u72f4\u5eb3\u610e\u6ed7\u6fde\u5f3c\u59a3\u5a62\u5b16\u74a7\u8d32\u7540\u94cb\u79d5\u88e8\u7b5a\u7b85\u7be6\u822d\u895e\u8df8\u9ac0", bian: "\u97ad\u8fb9\u7f16\u8d2c\u6241\u4fbf\u53d8\u535e\u8fa8\u8fa9\u8fab\u904d\u533e\u5f01\u82c4\u5fed\u6c74\u7f0f\u7178\u782d\u78a5\u7a39\u7a86\u8759\u7b3e\u9cca", biao: "

ansible 结合playbook批量添加用户

ansible 批量添加用户,结合playbook脚本实现远程主机批量添加用户 1.模块介绍: with_items with_items 是 playbook 标准循环,最常用到的就是它,with_items 可以用亍迭代一个列表戒字典,通过{{ item }}获取每次迭代的值(注意语法格式) --- - hosts: all #remote_user: root tasks: - user: name="{{item.name}}" group="{{item.group}}" password="{{‘lxkj’|password_hash(‘sha512’)}}" with_items: - {name: “lixingyu”, group: “root”} - {name: “gaopan”, group: “develop”} - {name: “wanghong”, group: “develop”} - {name: “maoyonggang”, group: “develop”} - {name: “majingtao”, group: “develop”} 2.测试脚本 通过 ansible-playbook -C去测试脚本是否正确 lx@ansible:~/playbook$ ansible-playbook -C useradd.yaml PLAY ******************************************************************************** TASK [setup] ************************************************************************ ok: [10.37.*.*] ok: [10.37.*.*] ok: [10.37.*.*] ok: [10.

怎样通过历史数据预测未来?

很多人或许都看过火影忍者,你是否对蛤蟆丸口中的预言之子感到很神奇,这个老蛤蟆预言了很多事情,他在梦里可以预见未来。如果我们在现实生活中也能预测未来该有多好,每天坐等买彩票就可以致富了(笑醒)。当然彩票因为其随机性,肯定是不能预测的,不过有些事情倒是可以预测,只是现有的技术还做不到百分百正确。那么哪些事情是可以预测的呢,比如预测天气、预测股票,预测世界杯或NBA,预测疾病,事故,公司明年的销量,未来的房价走向等等。其实预测可以用于几乎每个行业,通过预测可以对一些决策提供客观参考。那么怎么做到预测呢?下面我们通过一个简单的示例来理解预测。 假设有这样一个场景,每天上下班的时候,我们乘坐的电梯有时候会出故障,有的电梯一下掉十几楼,我每天坐电梯的时候心都是提着的。那么我们是否可以对某部电梯的故障进行预测,来减少未来发生故障的次数?当然可以的。 选用较为主流的一些工具来搭建我们的预测环境。 jupyter安装:https://www.cnblogs.com/bxyan/p/7203966.html可以参照该文章进行安装 hadoop安装:https://blog.csdn.net/hliq5399/article/details/78193113安装本地模式就可以了 spark安装:https://www.cnblogs.com/tijun/p/7561718.html 由于spark是运行在hdfs上,所以需要先安装好hadoop 以上环境搭建好了后,我们就以hadoop为数据源,来计算预测模型,再以该模型实时预测电梯故障。 我们采集到电梯正常运行和故障发生前的一些数据: 运行时长 200370130245360365345361112190234564670200240490785280150530489389载重5001009003007009005552331000110023460030011009004001000120011899991001009是否高峰期1010110011010110011101是否故障0000000000011111111111 我们将其中的70%作为训练数据,30%作为测试数据。首先利用训练数据训练出预测模型。我们用pyspark从hadoop中提取出数据: import findspark import os #初始化pyspark的依赖 findspark.init() %matplotlib inline # 实例化sparksession from pyspark.sql import SparkSession spark = SparkSession.builder \ .master("local") \ .appName("Python Spark SQL basic example") \ .config("spark.some.config.option", "some-value") \ .enableHiveSupport() \ .getOrCreate() spark实例已经初始化成功,接下来从hadoop中提取数据到spark中, #提取hadoop数据到DataFram df_train = spark.read.format("csv").option("header","true")\ .option("inferSchema","true").load("hdfs://bigdata:8020/hive/warehousedir/db.db/lift/lift_train.txt") df_train.show() 接下来需要将这些数据构造成特征矩阵,其中feature列就是转换后的特征矩阵 from pyspark.ml.feature import * vectorizer = VectorAssembler() vectorizer.setInputCols(["runtime", "weight", "ishight"]) vectorizer.setOutputCol("features") #特征矩阵 df_vect = vectorizer.transform(df_train) df_vect.show() 我们这里选用的是逻辑回归算法来生成模型,因为我们预测的目标属性是一个二元数值。生成模型的算法还有很多,按模型的训练方式分为:有监督训练、无监督训练和半监督训练。逻辑回归是监督训练中的一种,决策树算法,神经网络,多元线性回归等也都属于监督训练。

Docker系列05—Docker 存储卷详解

1.1 背景 (1)docker 的 AFUS 分层文件系统 docker镜像由多个只读层叠加面成,启动容器时,docker会加载只读镜像层并在镜像栈顶部加一个读写层; 如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件版本仍然存在,只是已经被读写层中该文件的副本所隐藏,此即“写时复制(COW)”机制。 (2)示意图 描述:如果一个文件在最底层是可见的,如果在layer1上标记为删除,最高的层是用户看到的Layer2的层,在layer0上的文件,在layer2上可以删除,但是只是标记删除,用户是不可见的,总之在到达最顶层之前,把它标记来删除,对于最上层的用户是不可见的,当标记一删除,只有用户在最上层建一个同名一样的文件,才是可见的。 1.2 为什么要使用存储卷 对于这类的操作,修改删除等,一般效率非常低,如果对一于I/O要求比较高的应用,如redis在实现持化存储时,是在底层存储时的性能要求比较高。 假设底层运行一个存储库mysql,mysql本来对于I/O的要求就比较高,如果mysql又是运行在容器中自己的文件系统之上时,也就是容器在停止时,就意味着删除,其实现数据存取时效率比较低,要避免这个限制要使用存储卷来实现。 存在的问题: 存储于联合文件系统中,不易于宿主机访问; 容器间数据共享不便 删除容器其数据会丢失 1.3 存储卷 (1)介绍 “卷”是容器上的一个或多个“目录”,此类目录可绕过联合文件系统,与宿主机上的某个目录“绑定(关联)”; 类似于挂载一样,宿主机的/data/web目录与容器中的/container/data/web目录绑定关系,然后容器中的进程向这个目录中写数据时,是直接写在宿主机的目录上的,绕过容器文件系统与宿主机的文件系统建立关联关系,使得可以在宿主机和容器内共享数据库内容,让容器直接访问宿主机中的内容,也可以宿主机向容器供集内容,两者是同步的。 mount名称空间本来是隔离的,可以让两个本来是隔离的文件系统,在某个子路径上建立一定程度的绑定关系,从而使得在两个容器之间的文件系统的某个子路径上不再是隔离的,实现一定程度上共享的效果。 在宿主机上能够被共享的目录(可以是文件)就被称为volume。 (2)存储卷作用 优点是容器中进程所生成的数据,都保存在存储卷上,从而脱离容器文件系统自身后,当容器被关闭甚至被删除时,都不用担心数据被丢失,实现数据可以脱离容器生命周期而持久,当再次重建容器时,如果可以让它使用到或者关联到同一个存储卷上时,再创建容器,虽然不是之前的容器,但是数据还是那个数据,特别类似于进程的运行逻辑,进程本身不保存任何的数据,数据都在进程之外的文件系统上,或者是专业的存储服务之上,所以进程每次停止,只是保存程序文件,对于容器也是一样;容器就是一个有生命周期的动态对象来使用,容器关闭就是容器删除的时候,但是它底层的镜像文件还是存在的,可以基于镜像再重新启动容器。 但是容器有一个问题,一般与进程的启动不太一样,就是容器启动时选项比较多,如果下次再启动时,很容器会忘记它启动时的选项,所以最好有一个文件来保存容器的启动,这就是容器编排工具的作用。一般情况下,是使用命令来启动操作docker,但是可以通过文件来读,也就读文件来启动,读所需要的存储卷等,但是它也只是操作一个容器,这也是需要专业的容器编排工具的原因。 另一个优势就是容器就可以不置于启动在那台主机之上了,如几台主机后面挂载一个NFS,在各自主机上创建容器,而容器上通过关联到宿主机的某个目录上,而这个目录也是NFS所挂载的目录中,这样容器如果停止或者是删除都可以不限制于只能在原先的宿主机上启动才可以,可以实现全集群范围内调试容器的使用,当再分配存储、计算资源时,就不会再局限于单机之上,可以在集群范围内建立起来,基本各种docker的编排工具都能实现此功能,但是后面严重依赖于共享存储的使用。 (3)配合各服务应用状态分析 考虑到容器应用是需要持久存储数据的,可能是有状态的,如果考虑使用NFS做反向代理是没必要存储数据的,应用可以分为有状态和无状态,有状态是当前这次连接请求处理一定此前的处理是有关联的,无状态是前后处理是没有关联关系的,大多数有状态应用都是数据持久存储的,如mysql,redis有状态应用,在持久存储,如nginx作为反向代理是无状态应用,tomcat可以是有状态的,但是它有可能不需要持久存储数据,因为它的session都是保存在内存中就可以的,会导致节点宕机而丢失session,如果有必要应该让它持久,这也算是有状态的。 应用状态象限:是否有状态或无状态,是否需要持久存储,可以定立一个正轴坐标系,第一象限中是那些有状态需要存储的,像mysql,redis等服务,有些有有状态但是无需进行存储的,像tomcat把会话保存在内存中时,无状态也无需要存储的数据,如各种反向代理服务器nginx,lvs请求连接都是当作一个独立的连接来调度,本地也不需要保存数据,第四象限是无状态,但是需要存储数据是比较少见。 运维起来比较难的是有状态且需要持久的,需要大量的运维经验和大量的操作步骤才能操作起来的,如做一个Mysql主从需要运维知识、经验整合进去才能实现所谓的部署,扩展或缩容,出现问题后修复,必须要了解集群的规模有多大,有多少个主节点,有多少个从节点,主节点上有多少个库,这些都要一清二楚,才能修复故障,这些就强依赖于运维经验,无状态的如nginx一安装就可以了,并不复杂,对于无状态的应用可以迅速的实现复制,在运维上实现自动化是很容易的,对于有状态的现状比较难脱离运维人员来管理,即使是k8s在使用上也暂时没有成熟的工具来实现。 总之:对于有状态的应用的数据,不使用存储卷,只能放在容器本地,效率比较低,而导致一个很严重问题就是无法迁移使用,而且随着容器生命周期的停止,还不能把它删除,只能等待下次再启动状态才可以,如果删除了数据就可能没了,因为它的可写层是随着容器的生命周期而存在的,所以只要持久存储数据,存储卷就是必需的。 docker存储卷难度:对于docker存储卷运行起来并不太麻烦,如果不自己借助额外的体系来维护,它本身并没有这么强大,因为docker存储卷是使用其所在的宿主机上的本地文件系统目录,也就是宿主机有一块磁盘,这块磁盘并没有共享给其他的docker主要,然后容器所使用的目录,只是关联到宿主机磁盘上的某个目录而已,也就是容器在这宿主机上停止或删除,是可以重新再创建的,但是不能调度到其他的主机上,这也是docker本身没有解决的问题,所以docker存储卷默认就是docker所在主机的本地,但是自己搭建一个共享的NFS来存储docker存储的数据,也可以实现,但是这个过程强依赖于运维人员的能力。 1.4 存储卷原理 volume于容器初始化之时会创建,由base image提供的卷中的数据会于此期间完成复制 volume的初意是独立于容器的生命周期实现数据持久化,因此删除容器之时既不会删除卷,也不会对哪怕未被引用的卷做垃圾回收操作 卷为docker提供了独立于容器的数据管理机制 可以把“镜像”想像成静态文件,例如“程序”,把卷类比为动态内容,例如“数据”,于是,镜像可以重用,而卷可以共享 卷实现了“程序(镜像)"和”数据(卷)“分离,以及”程序(镜像)“和"制作镜像的主机”分离,用记制作镜像时无须考虑镜像运行在容器所在的主机的环境 1.5 存储卷分类 Docker有两种类型的卷,每种类型都在容器中存在一个挂载点,但其在宿主机上位置有所不同; Bind mount volume(绑定挂载卷):在宿主机上的路径要人工的指定一个特定的路径,在容器中也需要指定一个特定的路径,两个已知的路径建立关联关系 Docker-managed volume(docker管理卷): 只需要在容器内指定容器的挂载点是什么,而被绑定宿主机下的那个目录,是由容器引擎daemon自行创建一个空的目录,或者使用一个已经存在的目录,与存储卷建立存储关系,这种方式极大解脱用户在使用卷时的耦合关系,缺陷是用户无法指定那些使用目录,临时存储比较适合; 2、使用存储卷 为docker run 命令使用-v 选项即可使用volume docker-managed volume docker run -it -name rbox1 -v /data busybox #/data指定docker的目录 docker inspect -f {{.