wireshark笔记 2022.9.15 CIDR名词解释wireshark入门功能历史原理优势下载安装基本使用选择网卡 wire shark界面 伯克利包过滤规则语法规则案例演示筛选过滤器(显示过滤器)捕获过滤器案例演示 捕获文件的保存杂项设置内置文件路径默认配置 CIDR名词解释 CIDR(无类别域间)是一个在Internet上创建附加地址的方法,这些地址提供给服务提供商(ISP),再由ISP分配给客户。CIDR将路由集中起来,使一个IP地址代表主要骨干提供商服务的几千个IP地址,从而减轻Internet路由器的负担 wireshark入门 功能 网络流量捕获和分析的软件 历史 Ethereal是Wireshark的前身,2006年更名为wireshark 原理 捕获二进制流量转换wireshark组装数据包分析捕获的数据包、识别协议等信息 优势 开源免费跨平台可视化功能强大,支持协议种类多 下载安装 官网 https://www.wireshark.org 基本使用 选择网卡 查询到kali中的对外网卡名称为eth0 ──(root💀newkali)-[~] └─# ip a 130 ⨯ 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP link/ether 00:0c:29:b2:f0:10 brd ff:ff:ff:ff:ff:ff inet 10.
Table固定表头和首列这种需求应该比较常见。以往的做法,需要写一大堆脚本,而现在,可以使用position:sticky轻松实现这个效果。
.table-container { width: 100%; height: 100%; overflow: auto; } /* 首列固定 */ .table-container thead tr > th:first-child, .table-container tbody tr > td:first-child { position: sticky; left: 0; z-index: 1; } /* 表头固定 */ .table-container thead tr > th { position: sticky; top: 0; z-index: 2; } /* 表头首列强制最顶层 */ .table-container thead tr > th:first-child { z-index: 3; } HTML结构上,必须将 <table> 放在 <div class="table-container"> 子节点,且内部不要有其他 position 设置。
下面语句主要用于根据数据库字段进行按天、按月、按年分组统计时的查询,仅做个人收藏备用。
1、如果时间字段类型为date或datetime:
按周查询
SELECT DATE_FORMAT(create_time,'%Y%u') weeks,
COUNT(id) count FROM order
where channel_code =#{channelCode}
GROUP BY weeks
order by count desc按天查询
SELECT DATE_FORMAT(created_at,'%Y-%m-%d') days,
COUNT(id) count FROM order
where channel_code =#{channelCode}
GROUP BY days
order by count desc按月查询
SELECT DATE_FORMAT(create_time,'%Y%m') months,
COUNT(id) count FROM order
where channel_code =#{channelCode}
GROUP BY months
order by count desc 2、如果时间字段为时间戳(timestamp)或int表示的时间戳:
按周查询
SELECT FROM_UNIXTIME(create_time,'%Y%u') weeks,
COUNT(id) count FROM order
where channel_code =#{channelCode}
GROUP BY weeks
Linux文件管理和 I/O 重定向 Linux文件系统目录结构 常见目录说明: /:根目录,一般根目录下只存放目录,在Linux下有且只有一个根目录。所有的东西都是从这里开始。当你在终端里输入“/home”,你其实是在告诉电脑,先从/(根目录)开始,再进入到home目录。
/bin: /usr/bin: 可执行二进制文件的目录,如常用的命令ls、tar、mv、cat等。
/boot:放置linux系统启动时用到的一些文件,如Linux的内核文件:/boot/vmlinuz,系统引导管理器:/boot/grub。
/dev:存放linux系统下的设备文件,访问该目录下某个文件,相当于访问某个设备,常用的是挂载光驱 mount /dev/cdrom /mnt。
/etc:系统配置文件存放的目录,不建议在此目录下存放可执行文件,重要的配置文件有 /etc/inittab、/etc/fstab、/etc/init.d、/etc/X11、/etc/sysconfig、/etc/xinetd.d。
/home:系统默认的用户家目录,新增用户账号时,用户的家目录都存放在此目录下,表示当前用户的家目录,edu 表示用户 edu 的家目录。
/lib: /usr/lib: /usr/local/lib:系统使用的函数库的目录,程序在执行过程中,需要调用一些额外的参数时需要函数库的协助。
/lost+fount:系统异常产生错误时,会将一些遗失的片段放置于此目录下。
/mnt: /media:光盘默认挂载点,通常光盘挂载于 /mnt/cdrom 下,也不一定,可以选择任意位置进行挂载。
/opt:给主机额外安装软件所摆放的目录。
/proc:此目录的数据都在内存中,如系统核心,外部设备,网络状态,由于数据都存放于内存中,所以不占用磁盘空间,比较重要的目录有 /proc/cpuinfo、/proc/interrupts、/proc/dma、/proc/ioports、/proc/net/* 等。
/root:系统管理员root的家目录。
/sbin: /usr/sbin: /usr/local/sbin:放置系统管理员使用的可执行命令,如fdisk、shutdown、mount 等。与 /bin 不同的是,这几个目录是给系统管理员 root使用的命令,一般用户只能"查看"而不能设置和使用。
/tmp:一般用户或正在执行的程序临时存放文件的目录,任何人都可以访问,重要数据不可放置在此目录下。
/srv:服务启动之后需要访问的数据目录,如 www 服务需要访问的网页数据存放在 /srv/www 内。
/usr:应用程序存放目录,/usr/bin 存放应用程序,/usr/share 存放共享数据,/usr/lib 存放不能直接运行的,却是许多程序运行所必需的一些函数库文件。/usr/local: 存放软件升级包。/usr/share/doc: 系统说明文件存放目录。/usr/share/man: 程序说明文件存放目录。
/var:放置系统执行过程中经常变化的文件,如随时更改的日志文件 /var/log,/var/log/message:所有的登录文件存放目录,/var/spool/mail:邮件存放的目录,/var/run:程序或服务启动后,其PID存放在该目录下。
说明:
文件和目录被组织成一个单根倒置树结构文件系统从根目录下开始,用“/”表示根文件系统(rootfs): root filesystem标准Linux文件系统(如: ext4),文件名称大小写敏感,例如:MAIL, Mail, mail, mAilL以 . 开头的文件为隐藏文件路径分割的 /文件名最长255个字节包括路径在内文件名称最长4095个字节蓝色–> 目录 绿色–>可执行文件 红色–>压缩文件 浅蓝色–>链接文件 灰色–>其它文件每个文件都有两类相关数据:元数据:metdata,即属性,数据:data,即文件内容。 Linux下的文件类型 - 普通文件 d 目录文件directory | 符号1链接文件link b 块设备block c 字符设备character p 管道文件pipe s 套接字文件socket 范例: [root@Centos7 ~]# ls -l /run/ -rw-r--r-- 1 root root 4 Aug 10 13:25 acpid.
效果图
<div class="msgNotice" v-if="mesData.length>0"> <div class="msgInsideStrip"> <img src="~/Content/fimg/horn-white.png" /> <div id="affiche_real"> <div class="affiche_text"></div> </div> </div> </div> h5代码
//vue方法 获取需要滚动的文字 调用滚动方法 getMessDate: function () { var that = this; $.post("@Url.Action("GetMessages", "MessagesApi")", function (res) { that.mesData = []; that.mesData = res.data; if (res.data.length > 0) { that.$nextTick(function () { that.marquee(); }); } }); }, //滚动方法 marquee: function () { var scrollWidth = $('#affiche_real').width(); //滚动区域宽度 var index = 0; $('.affiche_text').text(layoutEl.mesData[index]); var textWidth = $('.
1.所有版本QT下载地址 2.所有Qt Creator下载地址
3. 所有Qt VS开发插件下载地址
4.Qt官网镜像下载地址
4.Qt开原版资源汇总下载地址
在anaconda环境下使用pip安装包时,有以下错误:
Cache entry deserialization failed, entry ignored
Could not fetch URL https://pypi.tuna.tsinghua.edu.cn/simple/tensorflow/: There was a problem confirming the ssl certificate: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:748) - skipping
Could not find a version that satisfies the requirement tensorflow==1.4.0 (from versions: )
No matching distribution found for tensorflow==1.4.0
发现是对源网站的证书不信任,所以在pip的过程中加入信任网站即可,如下:
pip install tensorflow==1.4.0 --trusted-host pypi.tuna.tsinghua.edu.cn
使用axios 调用接口报错 Cannot get/api/test 重装请求模块!!
npm remove request
npm install requset
解决!!!**
前面我们了解了晶振的结构,也了解了晶振的模型,这一节就来看看晶振是如何起振的。
皮尔斯晶体振荡器
目前工作中用得最多的就是皮尔斯晶体振荡器,也就是下面这个结构。
CL1,CL2为匹配电容,Rext通常为串联的几百欧姆电阻(有时也不加)。上面这个结构可能看着不是很熟悉,我们把它转换一下,变成下面这个就熟悉些。
上图中把RF忽略掉了,如果用过无源晶振的话,应该知道这个RF的阻值一般是很大的,兆欧姆级别,其作用主要是为了给反相放大器一个合适偏置。就像我们模电里面的三极管电路,其工作时都需要合适的直流偏置,这里我们先忽略掉。
结合上一章节说的晶振的等效电路
我估计有人看到这里就跑了,这一坨是什么东西,搞这么复杂?其实没那么难,这里面所有的器件,除了反相放大器外,都是基本元器件,反而是更容易分析的。
不过在这之前呢?我们还是插播一个知识点,那就是起振条件。因为只有搞懂了起振条件,我们才能知其然并且知其所以然,先理论分析,然后用仿真去验证,如此更爽。
起振条件
起振条件有两个:相位和环路增益
上图中将反相放大器的传递函数用A(s)表示,晶振及其匹配电路打包一起,其传递函数看作F(s)。
当环路增益大于1时,说明输入信号在环路中逛一圈后又送到输入端,信号幅度比原来更大
相位为2nπ,说输入信号在电路中逛一圈后,相位与原本的输入信号完全相同,因此输入信号被完美的加强了。
两者结合,就形成了这样的情况:信号经过反复放大后,不断增大,最终就是我们看到那样。
当环路中的信号幅度增大到一定程度后,振荡器中的有源器件(晶振电路中的反相器)存在的非线性会限制幅度的继续增加,使得振荡器的输出达到稳定。通俗说就是振荡的幅值肯定超不过电源电压。
也就是说,只要满足那两个条件,再小的信号,经过环路的无限循环(输入信号Vin逛一圈变成更大的Vin,然后再逛一圈变成更更大的Vin,然后再逛一圈。。。),最终输出幅度总会起来。
尽管我们没有专门提供对应频率的输入信号Vin,但是电路中总会有噪声,比如白噪声就是全频段的,虽然信号很小,但是因为电路的这个不断加强的特性,所以最终一定有输出信号。也就是说,起振是必然的。
总之,起振要满足这两个条件:
关于晶振起振,有一个准则叫巴克毫森稳定性准则,想深入去看的同学可以去查查。
起振电路分析
上期说完了起振条件,那我们继续分析前面的电路,先看相位。
相位
相位需要满足2nπ,显然,n不可能等于0,等于零意外着完全没有相移,电路中有反相放大器,已经相移了π,也就是180°。所以最可能的就是晶振那一坨电路也让信号相移180度,整体凑够360°,也就是2π。
Rext和匹配电容CL1构成一个低通滤波器,带来的相移是小于90°的,这应该很容易知道,下图是Rext=100Ω,CL1=10p的低通滤波器的幅频曲线,可以看到,输入与输出的相位差是:0°~90°,输出滞后输入。
Rext和匹配电容CL1带来的相移是小于90°,那么晶振与CL2带来的相移必须大于90°,如此才能凑够180°。
那么什么时候晶振与CL2带来的相移是大于90°的呢?答案是必须晶振等效电路整体呈电感性才有可能。
晶振等效电路有三种元器件构成,电阻,电感,电容,其总的等效阻抗可能有三种情况:呈阻性,呈容性,呈感性。
如果从数学角度来看,晶振总阻抗公式化简之后总能写成一个复数的形式,包含实数和虚数的表达式:Z=R+jX。其中R是电阻分量,X为电抗分量。
当X=0:Z=R,整体呈阻性
当X>0:Z=R+jX,整体呈感性
当X<0:Z=R+jX,整体呈容性。
下面分别看下三种情况下,晶振与匹配电容CL2的相位情况。
阻抗公式算出来肯定是一大坨的,就不列了,我们直接看仿真,这样更为直观(电阻100只是象征性取值,可以取其它的,不影响结果,电容值也是)
可以看到,只有晶振在呈感性的时候,相移才能大于90°,其相移范围是:0~180°。
综上所述,晶振工作时呈感性。那么,晶振呈感性的频率范围是多少呢?
晶振呈感性频率范围
阻抗呈感性的频率范围,列出晶振的总阻抗公式就好了。
理论上说,总阻抗是个复数,我们可以把它化简成实部和虚部,虚部大于0时,即表示晶振呈感性。不过这也太费劲,还是直接搞一个实际的晶振参数看看。
大多数晶振都是没有给出Lm,Rm,Cm参数的,不过我查到爱普生的晶振有写出来,比如下面这款25Mhz的晶振。
可以看到,Rm最大为80Ω,动态电容Cm=1.94fF,动态电感Lm=20.91mH,静态电容C0=0.6pF。
我们直接用这些参数,采用LTspice仿真的方式画出阻抗曲线吧。
仿真的原理很简单,给一个1A的电流源,那么Vz的电压就是阻抗乘以电流,电流为1A,那么Vz的值就是阻抗值,因此,图中左边的dB幅度值就是阻抗值。相位表示电压超前电流的相角,因此,如果相位大于0,表示整体阻抗是感性,若小于0,表示整体阻抗是容性的。
从图中可以看出,两个尖之间的区域,相角大于0,就是呈感性的区域,晶体振荡频率25Mhz正好处于这一区域。
从图上看,两个冒尖的频率分别是24.988623Mhz,25.028984Mhz,很容易猜到,两个冒尖的频点这么特殊,应该是串联谐振点和并联谐振点。
我们可以验证下,分别计算下串联谐振和并联谐振。
计算值fs=24.988619Mhz,仿真图读值fs=24.988623Mhz
计算值fa=25.0289844Mhz,仿真图读值fa=25.028984Mhz
可以看到,可以说完全一致。
因此,晶体工作频率范围为:
当 然,以上只是说晶振实际工作的频率处于这个之间,并不是说实际工作时频率变化范围有这么大,衡量稳定度是有个参数叫频偏,注意不要误解。
小结
本节就写到这里了,暂时只说明了相位关系,其实还有些问题没搞清楚。
比如这个:我们都知道实际应用中,改变匹配电容,可以微调晶振工作频率,所以实际工作频率跟匹配电容肯定有关系,应该是有关系式的。具体关系式我在一些资料中已经看到了,不过只知道个结果吧,还没搞清楚咋来的,暂时就先放着吧。
以上就是本期内容了,如果有问题,欢迎留言指出。
VS2022 + OpenGL GLFW Windows环境配置 目录 VS2022 + OpenGL GLFW Windows环境配置0. 前言1. 一些介绍2. Visual Studio及C++基础环境配置3. GLFW配置4. GLAD配置5. Hello World! 0. 前言 因为一些需求,我需要用OpenGL写一些东西,本来是要Linux的,这里选择在Windows上搭配宇宙第一IDE Visual Studio进行编码,然后在Linux上进行编译运行,后面会再补一个Linux的环境配置(其实也就几行)。这篇博客主要起备忘作用,以及给一些小朋友们看一下。
1. 一些介绍 首先简单介绍一下OpenGL,它仅仅是一套标准而非具体实现,它的实现是交给厂商去做的,这是基于C/C++的一个库,既然是库,就要绑定语言,此处我选择的是 宇宙最强语言 C++,上文提到OpenGL只是一个接口规范,比较常见的如GLFW、GLUT等等,那么我们就要选择库实现版本,我大概搜了一下别的教程,普遍都是选择的GLUT安装,这玩意上次更新在1998年,那时候C语言还不支持随处定义变量名,中国还没入世,我还没出生,早就被弃用的东西了,我也是不懂怎么这么多怀旧精神这么强的人。
关联一些链接:
OpenGL官网
Khronos官网
GLFW官网
推荐教程
本文链接
2. Visual Studio及C++基础环境配置 本文默认你安好了,没安好的自己去官网下一个就行,一般是推荐安装2022 community(我个人是用的2022 community preview,于本文区别不大),如果你是别的版本的,自行对照后文更改就行,此处不加赘述。
3. GLFW配置 首先新建一个C++项目
在项目名上右键,选择管理NuGet程序包。
输入glfw,点击安装
这样就算安完了
4. GLAD配置 打开GLAD在线服务,选择OpenGL版本、设置Profile为Core,然后点击生成。
会得到这样一个压缩包,下载下来
解压后直接把include文件夹拖到你编译器安装位置的include里
找不到这个位置的同学可以在解决方案资源管理器(Ctrl + ;)的外部依赖项里面随便查看一个文件的属性
可以看到它的完整路径,这个include文件夹就是我们需要的位置。
把src文件夹拖到你的项目源文件里
5. Hello World! 最后测试一下我们配置好了没有,输入以下代码(测试代码来自: 链接):
#include<glad/glad.h> #include<GLFW/glfw3.h> #include<iostream> void framebuffer_size_callback(GLFWwindow* window, int width, int height); int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); GLFWwindow* window = glfwCreateWindow(800, 600, "
import random from albumentations.augmentations.transforms import Solarize from albumentations.augmentations.transforms import ChannelShuffle from albumentations.augmentations.transforms import InvertImg iu=["1","2","3","4","5","6","7","8"] iao=random.choice(iu) print(iao) input_img = imageio.imread('/media/lenovo/新加卷/PointCloudUDA/input/PnpAda_release_data/ct_train/img/0004.png') def aug(input_img,iao): if iao==1: noise=iaa.AdditiveGaussianNoise(10,20) aug_img=noise.augment_image(input_img) if iao==7: noise=iaa.AdditiveGaussianNoise(10,30) aug_img=noise.augment_image(input_img) if iao==8: noise=iaa.AdditiveGaussianNoise(10,40) aug_img=noise.augment_image(input_img) if iao==2: contrast=iaa.GammaContrast((0.5, 2.0)) aug_img = contrast.augment_image(input_img) if iao==3: contrast_sig = iaa.SigmoidContrast(gain=(5, 10), cutoff=(0.4, 0.6)) aug_img = contrast_sig.augment_image(input_img) if iao == 4: contrast_lin = iaa.LinearContrast((0.6, 0.4)) aug_img = contrast_lin.augment_image(input_img) if iao == 5: transform = ChannelShuffle(p=1.
一、什么是token? 在计算机身份认证中是令牌(临时)的意思,在词法分析中是标记的意思。一般作为邀请、登录系
统使用。
Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器生成
一个Toke n便将此Token返回给客户端,以后客户端只需带上这个Token前来请求数据即可,无需再次
带上用户名和密码。
二、什么是session? 服务器为了保存用户状态而创建的一个特殊的对象。
当浏览器第一次访问服务器时,服务器创建一个session对象(该对象有一个唯一的id,一般称之为
sessionId),服务器会将sessionId以cookie的方式发送给浏览器。
当浏览器再次访问服务器时,会将sessionId发送过来,服务器依据sessionId就可以找到对应的
session对象。
三、token与session的区别? 1) token和session其实都是为了身份验证,session一般翻译为会话,而token更多的时候是翻译为
令牌;
2) session在服务器端会保存一份,可能保存到缓存、文件或数据库;
3) session和token都是有过期时间一说,都需要去管理过期时间;
4) token的思想是算法验证,session的思想是信息存储对比。 token是有多种方案的,可以设计成
无需存储,token同时也是跨域的,session是要存储的,存储在数据库的思想;
5)其实token与session的问题是一种时间与空间的博弈问题,session是空间换时间,而tbken是时
间换空间。两者的选择要看具体情况而定;
6)虽然确实都是“客户端记录,每次访问携带”,但 token 很容易设计为自包含的,也就是说,后端
不需要记录什么东西,每次一个无状态请求,每次解密验证,每次当场得出合法 /非法的结论。
一、问题描述与技术挑战 在实际工作中,我们发现许多业务场景中都有对某一数值型指标实时统计分位数的需求,一般要求计算结果有很高准确率同时具备极低的计算延迟,实现这类需求给数据RD的开发工作带来一定的挑战,其中主要的技术挑战包括以下三个方面:
无法对全量数据进行排序:由于在实时计算场景中是逐条处理数据的,无法对全量数据排序,进而无法获得全量数据的分位数
计算逻辑复杂,计算延迟高:即时在能够排序的场景中,高复杂度的排序操作也会带来很高的计算延迟,无法满足实时计算的低延迟要求
分位数结果无法聚合:两个计算得出的分位数结果无法像求和结果那样直接累加合并得到新的结果,这为分位数计算结果的存储方式带来挑战
针对上述问题,我们基于TDigest数据结构,实现了实时计算环境下的分位数计算方法,封装为基础组件并向上提供API接口,可以在不同的业务场景(内核性能、搜索性能、PUSH等)下提供实时、准确的分位数计算。
二、基础架构与解决方案 本节我们将从计算分位数的常用数据结构、我们实现分位数计算的基础架构、解决方案三部分介绍流式计算场景下的分位数计算方法:
2.1 分位数的常用数据结构 TDigest计算分位数
TDigest是一个简单,快速,精确度高,可并行化的近似百分位算法,被Spark, ES, Kylin等系统使用。TDigest的核心思想是通过聚类的方法将离散的数据点聚集为多个不同的质心,在通过线性插值法计算分位数,线性插值法是最简单的插值算法。
通俗的讲:传统方法是对离散的数据进行排序,在排序结果中直接获得分位数。而TDigest是将离散的数据聚类为多个质心,然后对质心进行近似的“排序”,最后通过插值法求取分位数。
如上图所示,将离散的数据点(图中无色的数据点)聚类为多个不同的质心(图中彩色的数据点),其中每个质心周围的数据点数决定了该质心所占的权重(图中质心的大小),最后通过对所有的质心进行排序,就可以使用线性插值法求取对应的分位数,其中数据点与质心的距离和权重关系如下图所示。
特别地,在每个TDigest创建时有一个重要的compression参数,主要用于在计算的精确度与空间复杂度之间做权衡:
当compression参数设置越大时,聚类得到的质心越多,则差分法求取的分位数精确度越高
当compression参数设置越大时,TDigest数据结构占用的存储空间越大,则分位数计算的空间复杂度越高
设置合适的compression参数,能够在提高计算准确率的同时,尽可能降低存储空间,从而满足业务的实际需求
为了帮助大家在做分位数计算时能够选取合适的参数,我们选择百万级的数据量(即统计100w个随机变量的分位数),在不同参数下的计算精确度和空间复杂的如下表所示:
针对上表所示的数据,我们将做出以下三点说明:
本次测试使用MergingDigest数据结构,该结构占用的空间与compression参数的取值有关,与统计的数据量无关;
随着数据量的增大,compression的取值应适当增大,能够有效提高计算的准确率
2.2 分位数组建的基础架构 由于实时分位数计算是一个常见统计方法,在许多业务场景都会提出类似的需求,对需求方关注的统计指标计算不同的分位数。
为节约人力成本,缩短迭代开发的时间周期,我们基于TDigest数据结构,封装了通用的基础组件,从而在不同的业务场景下快速实现实时分位数统计的开发。
如上图所示,在实时分位数计算的通用组件中,其基础架构和执行过程主要分为以下几个关键步骤:
从上游业务方读取需要统计分位数的原始数据
根据业务方需求的分组规则,按分组聚合为TDigest数据结构,将聚合结果存入Redis中,或与Redis中已存在对应的数据进行合并,以获取准确的计算结果
从TDigest结构中获取分位数的计算结果,并向上返回
综上所述,我们通过封装基础组件并向上提供API的方式,实现了通用、灵活且对应用方透明的分位数计算方法,能够保证实时性的同时,实现高准确率、低空间复杂度的分位数计算,目前已经在性能平台、搜索、PUSH等厂内多个业务需求中落地应用
2.3 整体实现方案 基于上述介绍的实时分位数基础组件,在厂内的大多数业务场景中,通常从消息队列中获取应用方上报的原始数据,经过一系列解析和计算后,将计算结果存储Doris等OLAP引擎或DB中,共需求方查询和生成对应报表,这是一个通用的解决方案。
根据上述分析,我们就可以得到一个分位数实时计算作业的基本架构,其架构模型如下图所示:
如上图所示,在厂内的环境中,实时分位数计算任务的常用基本架构主要包括以下几个关键步骤:
1)从消息队列中读取业务方上报的基础数据,并按业务逻辑进行数据解析;
2)通过FlatMap方法,按不同字段将一条数据展开为多条(具体内容将在第3节详细介绍);
3)根据业务设计的查询维度,按不同的key对数据进行分组操作
4)分别将每个key的数据合并为一个TDigest数据结构
5)将聚合后的数据与Redis中存储的数据进行合并,同时将合并结果写回Redis中
6)最后根据数据聚合结构,从每个分组对应的TDigest结构中获取对应的分位数
综过以上步骤,可以实现高实时性、高精确度和低空间复杂度的实时分位数计算方法,能够满足大多数实时分位数业务的需求,在更多的业务场景中可能需要根据实际需求进行适当的调整。
三、解决分位数无法聚合的问题 3.1 问题描述 在实际的业务需求中,我们可能需要按照不同的时间、查询维度等信息检索统计的分位数。但是,已经计算好的两个分位数结果是无法进行聚合操作的。
例如:针对手百APP的用户访问时长,我们可以将某一天中每个小时访问时长的和(SUM)进行累加,从而获得这一天的访问时长总和。但我们如果记录了每个小时中访问时长的80分位数,则无法对这些分位数进行聚合,即无法求得这一天中访问时长的80分位数。这种现象被称为分位数的“不可聚合性”
因此,在实际应用中,如果业务需求要对不同时间、不同维度下的指标分位数进行任意聚合、查询等操作,就为分位数的计算和存储提出新的技术挑战。
3.2 分位数聚合方案 针对上述问题,我们提出按所有查询维度进行提前聚合计算的解决方案,即针对每一种可能出现的查询维度组合,我们都提前计算分位数并存储,这样在查询过程中直接检索对应查询维度的聚合计算结果,在解决了分位数的“不可聚合性”问题的同时,也避免了重复的聚合计算带来的时间开销,缩短了查询耗时,提升了用户体验。
接下来,我们通过一个简单实例讲解具体的聚合计算方法:假设在某业务场景中,用户关注的查询维度共有三个字段,分别为:APP版本(app_version)、厂商(manufacturer)和客户端操作系统版本(os_version)。则对于任意维度组合的查询操作,用户有可能采用 2^3=8 种聚合查询方式。因此,我们通过排列组合的方式,枚举中所有可能的聚合查询方式,分别统计分位数。假设从上游读取到的部分数据如下表所示:
并且,如果对某一字段进行聚合查询,我们将该字段的取值记为关键词 “ALL”,则这条数据共对应2^3=8 种可能的聚合查询方式。为了模拟出8种不同的维度排列组合方式,我们利用二进制排列组合的方式,让每个字段严格对应二进制数据中的一位:如果该位的取值为0,则字段内容为上报的原始值(即上表中的实际取值);若该位的取值为1,则对应字段的取值记为关键词“ALL”。此外,二进制数据中从右至左每一位与字段的对应关系为:
第1位对应os_version
第2位对应manufacturer
第3位对应app_version
由此可得,任意字段聚合查询的排列如何方式如下表所示:
这样,我们就通过二进制排列组合的方式,枚举出所有可能的维度组合查询方式。在实际的计算过程中,可以利用流式计算的FlatMap算子,按照上述的排列组合方式,将一条数据扩展为多条数据,并进行分组聚合、计算分位数,将最终的计算结果存入Doris等存储引擎中供用户查询。此时,计算结果中实际已经包含了所有可能的聚合查询方式,业务方可以按需要直接查询到最终的分位数结果,而无需另外进行聚合计算操作,在有效提高查询效率的同时保证了用户体验。
四、结语 以上内容是我们从宏观的角度,对实时分位数计算方法的核心技术、基础架构和技术难点进行了简要介绍。如有任何问题或建议,欢迎大家随时沟通交流。
文章发表在 知乎:一种基于实时分位数计算的系统及方法
雨过天青云破处,这般颜色做将来
文章目录 前言一、资源在WEB-INF目录下二、SpringMVC拦截器2.1、拦截器执行的时机:2.3、拦截器实现的两种方式2.4、拦截器实现的步骤 总结 前言 时间不等人
一、资源在WEB-INF目录下 此目录下的动态资源,不可直接访问,只能通过请求转发的方式进行访问
@RequestMapping("/showIndex") public String showIndex(){ System.out.println("访问index.jsp"); return "index"; } @RequestMapping("/showMain") public String showMain(){ System.out.println("访问main.jsp"); return "main"; } 修改视图解析器的前缀
二、SpringMVC拦截器 针对请求和响应进行的额外的处理,在请求和响应的过程中添加预处理,后处理和最终处理
2.1、拦截器执行的时机: preHandle():在请求被处理之前进行操作,预处理postHandle():在请求被处理之后,但结果还没有渲染前进行操作,可以改变响应结果,后处理afterCompletion():所有的请求响应结束后执行善后工作,清理对象,关闭资源,最终处理 2.3、拦截器实现的两种方式 继承HandlerInterceptorAdapter的父类实现HandlerInterceptor接口,实现的接口,推荐使用实现接口的方式 2.4、拦截器实现的步骤 改造登录方法,在session中存储用户信息,用于进行权限验证 @RequestMapping("/login") public String login(String name, String pwd, HttpServletRequest request){ if("zar".equalsIgnoreCase(name) && "123".equalsIgnoreCase(pwd)){ //在session中存储用户信息,用于进行权限验证 request.getSession().setAttribute("users",name); return "main"; }else { request.setAttribute("msg","用户名或密码不正确!"); return "login"; } } 开发拦截器的功能,实现HandlerInterceptor接口,重写preHandle()方法 public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //是否登录过的判断 if(request.
vue的原理
vue2是基于订阅发布者模式,用ES5中的object.defiend.protype对所有属性进行劫持转化setter和getter,当数据变动时通知发布者,触发相应的回调。
vue在什么时候一定要使用$set
一是通过数组下标改变数组中的值的时候,二是给data中定义的对象添加新的属性,需要使用到 $set(target,key,value),这里面vue.set是挂载到vue1上,this.set是挂载到vue的原型对象上,源码里数组改变是用splice(index,1,value)实现的响应式。
自定义组件怎么使用v-model
自定义封装的组件,在子组件中配置model对象,prop是穿过来的值,event是值改变触发的函数,在props里接收数据,在子组件身上绑定函数。
都封装过什么组件
封装过轮播图,select下拉框,基于antddesign封装过datepicker组件
埋点怎么做,怎么排布合理
埋点就是记录页面中用户的行为,记录用户添加,删除,修改,查询行为发送给后端
数组去重
双重for循环配合splice,new set去重,for循环配合indexof去重
闭包,防抖,节流,垃圾回收
事实上
浏览器处理过什么兼容性问题
CSS里 *{margin:0;padding:0;}
给超出高度的标签设置overflow:hidden;或者设置行高line-height 小于你设置的高度。
因为img标签是行内属性标签,所以只要不超出容器宽度,img标签都会排在一行里,但是部分浏览器的img标签之间会有个间距。去掉这个间距使用float是正道
第一类:块状元素float后,有添加了横向的margin,在IE6下比设置的值要大(属于双倍浮动的bug)
解决方案:给float标签添加display:inline,将其转换为行内元素
第三类:设置较小高度的容器(小于10px),在IE6下不识别小于10px的高度;
解决方案:给容器添加overflow:hidden;
首页白屏怎么处理,加loading,骨架屏,路由懒加载,图片懒加载,预渲染。
WebScoket
WebScoket 是一种在单个 TCP 连接上进行全双工通信的协议。与 HTTP 不同,它以 ws:// 或 wss:// 开头(分别表示 WebScoket 和安全 WebScoket 连接)。一旦通信连接建立和连接打开后,消息交换将以双向模式进行,不必在浏览器(客户端)发送 request 之后服务器才能发送信息到浏览器,这时候服务器有主动权,可以随时发消息给浏览器(客户端),客户端和服务器之间的连接也会持续存在,直到其中任何一方(客户端或服务器)宕掉或主动关闭连接,双方才关闭连接。
webpack怎么组成
,做plagin和loader的插件,entry,output,model.
Echartss怎么组成,写没写过滚动条,双Y轴怎么实现
title,toolitip,Xaxis,Yaxis,series,datazoom,visualmap不同区域颜色区分,
vue双向绑定改变数组的7个方法,reserve会改变原数组吗
push,unshift,pop,shift,splice,sort,reverse,reserve会改变原数组
用过vuex吗,什么时候在vuex发请求
在action中发请求,请求的数据是多个组件的公用数据时
router和route的区别
router是操作路由的,存放路由的方法,router.push,router.replace,
route是获取路由信息的,是当前正在跳转路由的信息对象,获取name,path,params,query.
vue的常用修饰符
.stop阻止冒泡,.once触发一次,.prevent阻止默认行为,.self自身触发
如何获取子元素的父元素下的所有子元素并遍历
parentNode,childrenNode,for循环遍历
列表页面的展开以及收起 需求想法关键代码结尾 需求 由于公司新需求 ,写一个列表页 ,不上拉加载 ,点击加载更多去加载 还会有收起按钮 。大概效果如下图所示:
想法 1,一开始想的是直接对数组进行切割 。然后每次点击加载更多重新加载 。但是这样之前加载的 又会重新加载一遍 。
2,最终决定 采用 将 之前的数据 保存下来 每次点击更多的时候 先回到原来的数据 。
好了 废话不多说了 上代码
关键代码 template部分
<template> <div class="list"> <div class="title">列表的展开以及收起</div> <div class="list"> <div v-for="(item,index) in showList" :key="index" class="box"> <div>{{item.title}}{{index+1}}</div> <div>{{item.type}}</div> </div> </div> <div class="load-more" @click="getList"> <div>加载更多</div> <div class="put-on" @click.stop="putOn" v-show="showList.length>2">收起</div> </div> </div> </template> js部分
export default { name:'collspan' , data(){ return{ resList:[] ,//接口获取的数组 showList:[] ,//展示的数组 showAll:true ,//展示全部? } } , methods:{ getList(){ if(!
HTML语法 1.单标记2.双标记3.属性 1.单标记 HTML中是不区分大小写的,空格与回车在其中无效果
HTML中用于描述功能的符号称为“标记”,单标记是其中的一种。
单独使用单标记就可以表达完整的意思,使用一对尖括号将标记名称括起来就能表示一个单标记了。
换行单标记:
<br> 为了展示br单标记的效果,我们来看下面一段代码:
<html> <head> <meta charset="UTF-8"> <title>br标记示例</title> </head> <body> 这是第一行。 这是第二行。 这是第三行。 点赞 收藏 关注 </body> </html> 网页效果:
可以发现,代码中看似不同行的内容,在浏览器窗口中被显示在同一行,而这时候br单标签就能实现换行操作。
添加br标记:
<html> <head> <meta charset="UTF-8"> <title>br标记示例</title> </head> <body> 这是第一行。<br> 这是第二行。<br> 这是第三行。<br> 点赞<br> 收藏<br> 关注 </body> </html> 添加br标记后的网页效果:
单标签还有:
<HR> <!=绘制水平线--> <BASEFONT> <!=设置渲染文本时作为默认字体的基础字体值。--> <COL> <!=指定基于列的表格默认属性。--> ..... 2.双标记 双标记由首标记和尾标记两部分构成,必须成对使用;
首标记告诉Web浏览器从此处开始执行该标记所表示的功能;
尾标记告诉Web浏览器在此处结束该标记;
注意:左尖括号与右尖括号是任何标记的开始和结束,双标记中结束的标记总是在开始标记前加一个斜杠/
部分双标记示例:
<html>...</html><!=html开始与结束--> <head>...</head><!=头部内容--> <body>...</body><!=主体内容--> <b>...</b><!=加粗--> <i>...</i><!=斜体--> <u>...</u><!=下划线字体--> <p>...</p><!=段落o--> <s>...</s><!=删除线字体--> 为了展示标记的效果,我们看下面代码:
<html> <head> <meta charset="
参考链接:PCL1.12.1+VS2019+QT5.15.2+VTK9.1开发环境配置
win10+vs2019+pcl1.12.1安装教程 前期准备:vs2019和Cmake已安装好
1、在VS019中安装qt扩展插件 打开VS->扩展->管理扩展,在搜索框搜索并安装:
此方法很慢或者会一直失败,所以有另外一种方法:
qt镜像下载:清华大学开源镜像站
根据自己vs版本下载对应版本。
下载好后,直接双击,打开Vs->扩展
点击Qt VS Tools->Qt Options->add添加qt编译器的配置信息
2、PCl安装:PCL下载 安装PCL:
解压pcl-1.12.1-pdb-msvc2019-win64.zip
将解压得到的文件夹中的所有pdb文件都拷贝到安装目录…\PCL 1.12.1\bin中:
安装的时候选了Add PCL to the system PATH for all users,电脑会生成环境变量:此电脑—>属性—>高级系统属性—>高级—>环境变量,会生成如下四个变量:
没有请手动添加
点击path:添加
3、VTK编译 VTK详细配置
编译好后生成的文件:
将生成的文件全部复制粘贴到…\PCL 1.12.1\3rdParty\VTK下,直接覆盖掉之前的
vs2019配置pcl1.12.1
在vs2019一个项目中,打开属性管理器,
在vc++目录->包含目录 中添加以下7个目录:
vc++目录->库目录 中添加以下6个目录:
C/C++—>预处理器—>预处理器定义:
BOOST_USE_WINDOWS_H
NOMINMAX
_CRT_SECURE_NO_DEPRECATE
C/C++ ->所有选项->SDL检查 改为否
链接器—>输入—>附加的依赖项
将PCL 1.12.1\3rdParty\VTK\lib和PCL 1.12.1\lib这两个文件夹下的lib文件的Dubug版本添加到附加依赖项中
release版本: pcl_common.lib
pcl_features.lib
pcl_filters.lib
pcl_io.lib
pcl_io_ply.lib
pcl_kdtree.lib
pcl_keypoints.lib
pcl_ml.lib
pcl_octree.lib
pcl_outofcore.lib
pcl_people.lib
pcl_recognition.lib
pcl_registration.lib
pcl_sample_consensus.lib
pcl_search.lib
pcl_segmentation.lib
pcl_stereo.lib
定义:
forEach(callbackFn,thisArg)
callbackFn有以下参数: element数组当前项的值 index数组当前项的索引 array 数组对象本身 对数组的每个元素执行一次给定的函数。 map(callbackFn,thisArg)
创建一个新数组,这个新数组由原数组中的每个元素都调用一次提供的函数后的返回值组成。 filter(callbackFn,thisArg)
创建一个新数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。 区别:
1.forEach不会返回新数组,map和filter返回新数组;forEach会更改原数组,map和filter不会对原数组产生影响;
2.forEach中的return充当continue使用,只用于控制是否跳出当前循环;
3.map根据当前数组映射一个新的数组,返回新的被改变后的数组,需要return;
4.filter返回新的数组,在循环的时候判断true还是false,是true才会return;
如何使用
1.forEach主要用于改变当前数组里面的值 let arrOne = [ {name:'小明', age: 14}, {name:'小华', age: 11}, {name:'小红', age: 15}, {name:'小黄', age: 17}, ] arrOne.forEach(item => { item.name = item.name + 'update' }) console.log(arrOne) 2.filter主要用于过滤当前数组,找出符合条件的元素,返回一个新的数组,不会改变原数组 let arrOne = [ {name:'小明', age: 14}, {name:'小华', age: 11}, {name:'小红', age: 15}, {name:'小黄', age: 17}, ] let arrNew = arrOne.filter(item => { return item.
🎹 个人简介:大家好,我是 金鱼哥,CSDN运维领域新星创作者,华为云·云享专家,阿里云社区·专家博主
📚个人资质:CCNA、HCNP、CSNA(网络分析师),软考初级、中级网络工程师、RHCSA、RHCE、RHCA、RHCI、ITIL😜
💬格言:努力不一定成功,但要想成功就必须努力🔥
🎈支持我:可点赞👍、可收藏⭐️、可留言📝
运维要时刻关注漏洞情况并根据现在的版本而进行知识的更新,本例子就是2022年9月8日当天工作所遇到的问题,经过排查和测试后,最终成功解决并了解到更进一步的设置。
文章目录 📜免密登录设置失效📜排查过程📜处理方法📑临时方法📑最佳方式 💡总结 📜免密登录设置失效 一个老运维,要做免密登录,如果没特殊需求,当然一上来就是直接一条命令 ssh-keygen 噼里啪啦,然后拷贝秘钥 ssh-copy-id 就直接了事,更何况要管控一台新下发的机器(云平台,你懂的),当然是直接运行 ssh-copy-id 就直接完事。
谁知道一 ssh 测试,就提示要输入密码,啊这,没道理啊,咋会翻车呢?
📜排查过程 输入密码能登录到系统,之后查看messages和secure日志,正常得很。
之后查看sshd配置,发现与之前有些不同的配置地方,好像HostKey那里,多了ed25519这样的东西(算法类型)如:
[root@centos7-3 ~]# vim /etc/ssh/sshd_config #Port 22 #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: # The default requires explicit activation of protocol 1 #Protocol 2 # HostKey for protocol version 1 #HostKey /etc/ssh/ssh_host_key # HostKeys for protocol version 2 HostKey /etc/ssh/ssh_host_rsa_key #HostKey /etc/ssh/ssh_host_dsa_key HostKey /etc/ssh/ssh_host_ecdsa_key HostKey /etc/ssh/ssh_host_ed25519_key # Lifetime and size of ephemeral version 1 server key #KeyRegenerationInterval 1h #ServerKeyBits 1024 .
一、Unity工程发布成Standalone Exe后,它的Debug 信息保存位置如下: 二、示例 三、log文件
python可用于数据分析,有时候获得了数据需要导出以作其他作用。本文就介绍python导出excel表格的方法。
导出excel表格,python提供了两个库:xlwt,xlrd。本文只讨论下大致框架
import xlwt import xlrd #xlwt,xlrd是python将数据导入excel表格使用的库 wb = xlwt.Workbook() # 添加一个表 ws = wb.add_sheet('test') #添加数据使用.write函数(横坐标,纵坐标,内容)注意横纵坐标从0开始,横纵坐标即对于excel而言 ws.write(x坐标, y坐标, 导出内容) #例:ws.write(0, 0, '股票编号') # ws.write(0, 0, a),a是变量 #将数据导出,保存格式为xxx.xls。其中xxx与上文表名同步 #注意此处一定要保存为.xls形式,如果是xlsx会打不开 wb.save('test.xls') 参考资料:https://cloud.tencent.com/developer/article/1487903link
上面的代码使用的是xlwt库,保存格式为.xls。但如果数据较多,超过65536就会报出下面的错误:
ValueError: row index was 65536, not allowed by .xls format 为了解决这个问题,我们使用另一个更大范围的库:openpyxl
代码模板如下:
import openpyxl data = ... #此处是要写入的数据 wb = openpyxl.Workbook() ws = wb.create_sheet("test") #写数据函数cell,cell中column和row至少为1 ws.cell(row=x, column = y, value = data[x][y]) wb.save("绝对地址") 参考资料:https://blog.csdn.net/qq_24285815/article/details/98845430
本文作者水平有限,如有不足之处,请下方评论区指出,谢谢!
1.国产麒麟系统的前后端环境(redis、jdk、mysql、nginx)配置 主要参考下面这个链接:
国产中标麒麟操作系统nginx+tomcat+redis+mysql安装部署手册.docx-原创力文档 (book118.com)
2.Redis安装步骤(不用编译) 主要参考了下面三个链接:
Linux下Redis的安装和部署 - humor1314 - 博客园 (cnblogs.com)Linux安装redis和部署 - 达兔哥 - 博客园 (cnblogs.com)linux下安装redis_anrenxiao9916的博客-CSDN博客 2.1下载软件 下载方式有两种,一是在服务器中直接用wiget命令进行下载;另外一种是先在本地下载redis源码, 然后使用ftp复制服务器,本教程是在redis官网(Redis)下载的源码,版本是5.0.13.
2.2 安装软件 把下载得到的redis源码拷贝到哪里,哪里就是安装目录。本教程redis的安装目录在 /usr/local/slcyEnv .
使用 tar -zxf redis-5.0.13.tar.gz 命令解压源码
使用 cd redis-5.0.13 进入redis源码目录
使用 make 对源码进行编译
编译成功后,redis-5.0.13目录下会出现src、redis.conf文件夹,
进入src文件夹,使用make install 可以进行安装,安装成功如下图所示
在src文件夹中,使用 redis-server ,可以启动redis
2.3 redis后台运行 使用 vi /usr/local/redis/etc/redis.conf 将daemonize no 改成daemonize yes,开启redis后台启动
2.4 redis开机自启动 vi /etc/rc.local //在里面添加内容:/usr/local/slcyEnv/redis-5.0.13/src/redis-server /usr/local/slcyEnv/redis-5.0.13/redis.conf (意思就是开机调用这段开启redis的命令)
然后运行chmod +x /etc/rc.d/rc.local,确保开机时执行此脚本
3.JDK安装(不用编译) 麒麟系统默认安装openjdk,使用 java -version 命令可以查看。
很多同学在进行慕课练习时遇到无法访问数据文件的问题,如:
此时的错误信息往往为 “FileNotFoundError: [Errno 2] No such file or directory”,意思是文件找不到错误,没有这个文件或者目录。
正确的做法有两个:
1)找到下载的数据文件,一般位于“下载”目录中。直接选中该文件,右击选择“复制”。然后在指定目录存放该文件,比如在C盘temp目录,你可以先建立这个目录,打开后直接右击空白区域选择“粘贴”,如:
此时即可在代码中,通过明确的目录来说明数据文件的位置:
2)将该数据文件复制后,粘贴到当前PyCharm项目中,即在左边窗格中当前PyCharm项目名称上右击选择Paste(粘贴):
出现提示,确定即可:
此时即可在当前项目中看到这个数据文件:
PyCharm会自动打开该数据文件,可以通过点击右边上方粉红色区域的“Reload in GBK”等切换字符集以正确显示内容:
进一步点击右边上方的Python代码文件即可重新回到编辑界面:
此时无需在数据文件前增加目录也可以正常访问数据文件:
在谷歌官网下载的chrome浏览器,下载的是安装器,要通过联网安装,谷歌浏览器官网:https://www.google.com/intl/zh-CN/chrome/https://www.google.com/intl/zh-CN/chrome/ 最新版本的统一下载链接,通过以下链接下载的都是最新的,是谷歌的dl子域名链接。谷歌相关的各种网页都打不开的情况下,这类dl链接是可以打开的,所以不怕墙的。
msi软件包:
64位:https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise64.msi
32位:https://dl.google.com/dl/chrome/install/googlechromestandaloneenterprise.msi
exe离线包:
64位:https://dl.google.com/chrome/install/standalonesetup64.exe
32位:https://dl.google.com/chrome/install/standalonesetup.exe
linux,amd64的deb软件包:
https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
混沌工程简介 太空舱 python写的。
太空舱将故障注入:
云监控排障 kindling
一、问题:win11打开VMware虚拟机就蓝屏
解决办法:
(1)虚拟机设置里移除USB控制器、声卡和打印机;
(2)升级vmware到16
(3)在启用或关闭Windows功能 勾选上 Windows虚拟机监控程序平台 和 虚拟机平台 ;在这步启动电脑的过程中一直显示撤销更改,勾选不成功!!!
但是我在任务管理器中查看虚拟化是启动的:
(4)所以查找资料可能是win11家庭版的原因导致的,然后将系统升级成了win11专业版(换成专业版的密钥),成功解决问题。
1)升级的过程中可能会碰到问题:
win11更新失败正在撤销更改是。
解决办法参考:https://www.boledir.com/jc/12912.html
最后,我的是升级了win11系统后第三步没有勾选(尝试勾选还是不成功),就成功了。
参考 ImageNet Classification with Deep Convolutional Neural Networks - 云+社区 - 腾讯云
摘要 我们训练了一个大型的深度卷积神经网络,将ImageNet LSVRC -2010竞赛中的120万幅高分辨率图像分成1000个不同的类。在测试数据上,我们实现了top-1名的错误率为37.5%,top-5名的错误率为17.0%,大大优于之前的水平。该神经网络有6000万个参数和65万个神经元,由5个卷积层和3个完全连接的层组成,其中一些卷积层之后是最大汇聚层,最后是100路的softmax。为了使训练更快,我们使用了非饱和神经元和一个非常高效的GPU实现卷积运算。为了减少全连通层的过拟合,我们采用了最近开发的正则化方法“dropout”,该方法被证明是非常有效的。在ILSVRC-2012比赛中,我们也加入了该模型的一个变体,并获得了15.3%的前5名测试错误率,而第二名获得了26.2%的错误率。
1、开场白 四年前,Yann LeCun和他的合作者的一篇论文被领先的计算机视觉大会拒绝,理由是它使用了神经网络,因此没有提供关于如何设计视觉系统的见解。当时,大多数计算机视觉研究人员认为,视觉系统需要仔细地手工设计,使用对任务性质的详细了解。他们假设,在自然图像中对物体进行分类的任务永远不会通过简单地展示图像的例子以及它们包含在一个神经网络中的物体的名称来解决,而这个神经网络从这些训练数据中获取了所有的知识。在视觉研究社区中,许多人没有意识到的是,需要了解领域的程序员仔细手工工程的方法不能推广,同样,需要用功能强大的通用学习过程替代程序员的方法也不能推广。有了足够的计算和数据,学习就比编程更适合复杂的任务,这些任务需要集成许多不同的、有噪声的线索。
四年前,当我们还在多伦多大学(University of Toronto)的时候,我们被称为“监督”(SuperVision)的深层神经网络使我们在自然图像中识别物体的错误率降低了近一半,并引发了计算机视觉领域迟来的范式转变。图4显示了一些监视功能的示例。监督是从20世纪80年代被广泛研究的多层神经网络发展而来的。这些网络使用了多层特征检测器,这些检测器都是从训练数据中学到的。神经科学家和心理学家曾假设,这种特征探测器的层次结构将提供一种强有力的方法来识别物体,但他们不知道如何学习这种层次结构。在1980年代非常激动因为几个不同的研究小组发现,可以训练多层特征探测器有效使用相对简单的算法称为backpropagation来计算,对于每一个形象,整个网络的分类性能如何取决于重量在每个连接上的值。
反向传播可以很好地完成各种任务,但在20世纪80年代,它没有达到其倡导者的很高期望。特别是,事实证明,学习具有许多层的网络是非常困难的,而这些正是应该产生最令人印象深刻的结果的网络。许多研究人员错误地认为,从随机初始权重中学习深度神经网络太难了。20年后,我们知道哪里出了问题:为了让深层神经网络发光,它们需要更多的标记数据和大量的计算。
2、简介 目前的目标识别方法主要使用机器学习方法。为了提高性能,我们可以收集更大的数据集,学习更强大的模型,并使用更好的技术来防止过度拟合。直到最近,标记图像的数据集还相对较小——大约是数万张图像。使用这种大小的数据集可以很好地解决简单的识别任务,特别是如果使用保存标签的转换来增强它们。例如,MNIST数字识别任务的当前最佳错误率(<0.3%)接近人类性能。但现实环境中的物体表现出相当大的变异性,因此,要学会识别它们,有必要使用更大的训练集。事实上,小图像数据集的缺点已经得到了广泛的认识,但是直到最近才有可能收集数百万幅图像的标记数据集。新的更大的数据集包括由数十万张完全分割的图像组成的LabelMe,以及由超过22000个类别的超过1500万张高分辨率图像组成的ImageNet。
要从数以百万计的图像中学习成千上万的物体,我们需要一个具有较大学习能力的模型。然而,目标识别任务的巨大复杂性意味着即使是像ImageNet这样大的数据集也不能指定这个问题,因此我们的模型也应该具有大量的先验知识来补偿我们没有的所有数据。卷积神经网络(CNNs)就是其中一类模型。它们的容量可以通过改变深度和宽度来控制,而且它们还对图像的性质(即统计量的平稳性和像素依赖性的局部性)做出了强有力且基本正确的假设。因此,与具有相同大小层的标准前馈神经网络相比,CNNs具有更少的连接和参数,因此更容易训练,而从理论上讲,它们的最佳性能可能只会略差。
尽管CNNs具有吸引人的特性,尽管其局部架构相对高效,但将其大规模应用于高分辨率图像仍然非常昂贵。幸运的是,当前的GPU与高度优化的2D卷积实现相结合,具有足够强大的功能,可以方便地训练有趣的大型CNNs,而且最近的数据集(如ImageNet)包含足够多的标记示例,可以训练此类模型,而不会出现严重的过拟合。
本文的具体贡献如下:我们对ImageNet large Visual Recognition Challenge ILSVRC - 2010和ILSVRC - 2012比赛中使用的ImageNet子集进行了迄今为止最大的CNNs之一的训练,并取得了迄今为止在这些数据集中所报道的最好的结果。我们编写了一个高度优化的GPU实现的二维卷积和所有其他固有的训练CNNs的操作,我们公开可用。我们的网络包含了许多新的和不寻常的特性,这些特性提高了它的性能,减少了它的训练时间,这些特性在第4节中详细介绍。我们的网络规模使过度拟合成为一个重要的问题,即使有120万个标记的训练示例,所以我们使用了一些有效的技术来防止过度拟合,如第5节所述。我们最终的网络包含5个卷积和3个完全连接的层,这个深度似乎很重要:我们发现去掉任何卷积层(每个卷积层包含的参数不超过模型参数的1%)都会导致性能低下。
最后,网络的大小主要受到当前GPU上可用内存的大小和我们愿意忍受的训练时间的大小的限制。我们的网络需要5到6天的时间来训练两个GTX 580 3GB GPU。我们所有的实验都表明,只要等待更快的gpu和更大的数据集可用,我们的结果就可以得到改善。
3、数据集 ImageNet是一个超过1500万张高分辨率图像的数据集,属于大约22000个类别。这些图片是从网上收集的,并由人类贴标签者使用Amazon’s Mechanical Turk crowd-sourcing tool进行标记。从2010年开始,作为Pascal视觉对象挑战赛的一部分,每年都会举办一场名为ImageNet大型视觉识别挑战赛(ILSVRC)的比赛。ILSVRC使用ImageNet的一个子集,在1000个类别中每个类别大约有1000幅图像。总共大约有120万张训练图像、50,000张验证图像和150,000张测试图像。
ILSVRC-2010是唯一一个可以使用测试集标签的ILSVRC版本,因此这是我们进行大部分实验的版本。由于我们也在ILSVRC-2012竞赛中进入了我们的模型,所以在第7节中,我们也报告了这个版本的数据集的结果,对于这个版本的数据集,测试集标签是不可用的。在ImageNet上,通常报告两个错误率:top-1和top-5,其中top 5错误率是测试图像的一部分,其中正确的标签不在模型认为最可能出现的五个标签中。
ImageNet由可变分辨率的图像组成,而我们的系统需要一个恒定的输入维数。因此,我们将图像降采样到256×256的固定分辨率。对于给定的矩形图像,我们首先对图像进行重新标定,使较短的边长度为256,然后从得到的图像中裁剪出中心256×256的patch。除了从每个像素中减去训练集上的平均活动外,我们没有以任何其他方式对图像进行预处理。因此,我们将网络训练为像素的原始RGB值。
4、结构 图2总结了我们的网络架构。它包含八个学习层——五个卷积层和三个完全连接的层。下面,我们将描述我们的网络架构的一些新奇或不寻常的特性。第4.1 - 4.4节根据我们对其重要性的估计进行排序,最重要的放在第一位
4.1、整流线性单元的非线性 用或来模拟神经元输出f作为其输入x的函数的标准方法。在梯度下降训练时间方面,这些饱和非线性比非饱和非线性慢得多。继Nair和Hinton之后,我们将具有这种非线性的神经元称为整流线性单元(ReLUs)。使用ReLUs的深度CNNs训练速度是使用tanh单元的数倍。如图1所示,它显示了对于特定的四层卷积网络,在CIFAR-10数据集上达到25%的训练误差所需的迭代次数。这张图表明,如果我们使用传统的饱和神经元模型,我们就无法用这么大的神经网络来进行实验。
我们并不是第一个考虑CNNs中传统神经元模型的替代品。例如,Jarrett et al.13声称非线性f(x) = |tanh(x)|对于他们的对比归一化类型特别有效,然后是Caltech-101数据集中的局部平均池。然而,在这个数据集中,主要关注的是防止过度拟合,因此他们所观察到的效果不同于我们在使用ReLUs时报告的加速适应训练集的能力。更快的学习速度对大数据集上训练的大型模型的性能有很大的影响。
4.2、在多GPU上进行训练 一个GTX 580 GPU只有3GB的内存,这限制了可以在其上训练的网络的最大大小。事实证明,120万个训练实例足以训练一个GPU上无法容纳的网络。因此,我们将网络分布在两个GPU上。当前的GPU特别适合跨GPU并行化,因为它们可以直接读写彼此的内存,而不需要经过主机内存。我们使用的并行化方案本质上是将一半内核(或神经元)放在每个GPU上,还有一个额外的技巧:GPU只在特定的层中通信。这意味着,例如,第3层的内核从第2层的所有内核映射中获取输入。然而,第4层的内核只从位于同一GPU的第3层的内核映射中获取输入。对于交叉验证来说,选择连接模式是一个问题,但这允许我们精确地调整通信量,直到它是计算量的可接受部分。
结果的架构与“columnar”CNN的架构有些类似,只是我们的列不是独立的(参见图2)。该方案减少了我们(和前5错误率1.7%和1.2%,分别比净一半的内核在每个卷积层对准一个GPU。双GPU网络的训练时间比单GPU网络略短。
4.3、局部响应归一化 ReLUs有一个理想的特性,即不需要对输入进行标准化以防止其饱和。如果至少有一些训练例子对ReLU产生积极的输入,学习就会发生在那个神经元上。用代表神经元的激活,含义为在处使用核,然后使用ReLU激活函数响应归一化的表达式为:
其中和在相同空间位置上运行n个“相邻”内核映射,n是该层中内核的总数。当然,内核映射的顺序是任意的,并在培训开始之前确定。这种反应归一化实现了一种形式的横向抑制,其灵感来自于在真实神经元中发现的类型,在使用不同内核计算的神经元输出之间产生了对大型活动的竞争。常数k, n、α和β等超参数的值是决定使用一套验证;我们使用k = 2,n = 5,,β= 0.
傻瓜式教程 当你点击切换颜色的时候 用户登录背景图和登录按钮的背景图会随机发生变化,当然改别的也是可以的 俩个必备的条件 一 background-color: var(--background);css 样式属性要有 二 :style="{'--background':color}" 让谁变就在谁的标签上进行操作 代码
随机生成颜色 const Replacement = () => { let color = "#"; for (let i = 0; i < 6; i++) { let num = parseInt(Math.random() * 16); color += num.toString(16); } data.color = color; }
案例: 电梯最大载重量为 1000; 最后一个能进入电梯的人
select person_name from( select person_name, sum(weight) over(order by turn) t from Queue )t1 where t<=1000 order by t desc limit 1; 在hive中也是可以的
hive > select * from stu; OK stu.id stu.name 1 aa 2 bb 3 cc hive > select name from stu order by id desc; stu.name cc bb aa
有数据表 login 记录了用户登录的信息, 其中有一天登录多次的用户, 如下表所示
user_id login_date 1 2022-01-01 2 2022-01-01 1 2022-01-01 3 2022-01-01 ... ... 留存率 需求1: 求每天新增用户数量, 次留, 7日留, 15日留
# 先求每个用户首次登录的日期表, 首次登录日期当做新增的日期 with reg as( select user_id, min(login_date) as reg_date from login group by user_id) select reg.reg_date, count(distinct reg.user_id) as new_num, count(distinct if(datediff(login.login_date, reg.reg_date) = 1, login.user_id, null))/count(distinct reg.user_id) as remain_rate2, count(distinct if(datediff(login.login_date, reg.reg_date) = 7, login.user_id, null))/count(distinct reg.user_id) as remain_rate7, count(distinct if(datediff(login.login_date, reg.reg_date) = 15, login.
自己留档
double lat= 39.918888; double lon= 116.3976; // 设置当前地图显示为当前位置 aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon), 13)); MarkerOptions markerOptions = new MarkerOptions(); markerOptions.position(new LatLng(lat, lon)); markerOptions.title("当前位置"); markerOptions.visible(true); //BitmapDescriptor bitmapDescriptor = BitmapDescriptorFactory.fromBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.location_marker)); //markerOptions.icon(bitmapDescriptor); aMap.addMarker(markerOptions); 其实一句话就够了
aMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lon), 13)); 其他都是修饰
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
题目:利用C语言打印下列的几种类型的金字塔。 类型一: 代码:
#include<stdio.h> int main() { int i,j,k,n; for(i=0;i<=4;i++) { for(j=1;j<=2*i-1;j++) { printf("*"); } printf("\n"); } return 0; } 类型二: 代码:
#include<stdio.h> int main() { int i,j,k,n; for(i=1;i<=4;i++) { for(j=1;j<=7-2*(i-1);j++) { printf("*"); } printf("\n"); } return 0; } 类型三: 代码:
#include<stdio.h> int main() { int i,j,k; for(i=1;i<=4;i++) { for(j=0;j<2*i-1;j++) printf("*"); printf("\n"); } i=i-4; for(;i<=3;i++) { j=0; for(;j<5-2*(i-1);j++) printf("*"); printf("\n"); } return 0; } 类型四:(任意输入打印的行数) 代码:
#include<stdio.h> int main() { int i,j,k,n; printf("
解压文件
文件里没啥有用的内容,修改时间很特别到35年去了,注意到提示
而描述的时间戳为
再看一下文件的修改时间
想到的思路是,时间戳之差,根据经验猜测为ascii码,然后用python写了个脚本
#Author:Luci4n import os,time flag = "" origin_time = 2000000000 for i in range(0,47): file = r'./{0}.txt'.format(i) # 文件路径 get_time = int(os.path.getmtime(file)) #获取最近修改时间 key = get_time - origin_time flag += chr(key) print(flag) XMan{seems_to_be_related_to_the_special_guests}
1.为什么主键字段尽量要使用自增字段? 1.1性能角度
可以避免在数据页中,进行记录的挪动.自增时记录在数据页中是以追加的方式进行插入.
可能涉及到数据页分裂的情况,这时候需要申请一个新的数据页,然后挪动部分数据过去.
1.2存储利用率角度
数据页分裂后,原本存储率为100%的数据页下降到约为50%.
2.为什么主键字段长度尽量要小? 主键长度越小,普通索引(也叫辅助索引,二级索引)的叶子节点就越小,普通索引占用的空间也就越小.
🔗 运行环境:python3🚩 作者:K同学啊🥇 精选专栏:《深度学习100例》🔥 选自专栏:《新手入门深度学习》📚 推荐专栏:《Matplotlib教程》🧿 优秀专栏:《Python入门100题》 文章目录 一、前言二、LSTM的是什么三、准备工作1.设置GPU2.设置相关参数3.加载数据 四、数据预处理1.归一化2.时间戳函数 五、构建模型六、激活模型七、训练模型八、结果可视化1.绘制loss图2.预测3.评估 一、前言 今天是第10天,我们将使用LSTM完成股票开盘价格的预测,最后的R2可达到0.74,相对传统的RNN的0.72提高了两个百分点。
我的环境:
语言环境:Python3.6.5编译器:jupyter notebook深度学习环境:TensorFlow2.4.1 来自专栏:【深度学习100例】
往期精彩内容:
深度学习100例-卷积神经网络(LeNet-5)深度学习里的“Hello Word” | 第22天深度学习100例-卷积神经网络(CNN)实现mnist手写数字识别 | 第1天深度学习100例-卷积神经网络(CNN)服装图像分类 | 第3天深度学习100例-卷积神经网络(CNN)花朵识别 | 第4天深度学习100例-卷积神经网络(CNN)天气识别 | 第5天深度学习100例-卷积神经网络(VGG-16)识别海贼王草帽一伙 | 第6天深度学习100例-卷积神经网络(ResNet-50)鸟类识别 | 第8天深度学习100例-循环神经网络(RNN)股票预测 | 第9天 如果你还是一名小白,可以看看我这个专门为你写的专栏:《小白入门深度学习》,帮助零基础的你入门深度学习。
二、LSTM的是什么 神经网络程序的基本流程
一句话介绍LSTM,它是RNN的进阶版,如果说RNN的最大限度是理解一句话,那么LSTM的最大限度则是理解一段话,详细介绍如下:
LSTM,全称为长短期记忆网络(Long Short Term Memory networks),是一种特殊的RNN,能够学习到长期依赖关系。LSTM由Hochreiter & Schmidhuber (1997)提出,许多研究者进行了一系列的工作对其改进并使之发扬光大。LSTM在许多问题上效果非常好,现在被广泛使用。
所有的循环神经网络都有着重复的神经网络模块形成链的形式。在普通的RNN中,重复模块结构非常简单,其结构如下:
LSTM避免了长期依赖的问题。可以记住长期信息!LSTM内部有较为复杂的结构。能通过门控状态来选择调整传输的信息,记住需要长时间记忆的信息,忘记不重要的信息,其结构如下:
三、准备工作 1.设置GPU 如果使用的是CPU可以注释掉这部分的代码。
import tensorflow as tf gpus = tf.config.list_physical_devices("GPU") if gpus: tf.config.experimental.set_memory_growth(gpus[0], True) #设置GPU显存用量按需使用 tf.config.set_visible_devices([gpus[0]],"GPU") 2.设置相关参数 import pandas as pd import tensorflow as tf import numpy as np import matplotlib.
1. 定时器使用不当 1.1 time.After()的使用 默认的time.After()是会有内存泄露问题的,因为每次time.After(duration x)会产生NewTimer(),在duration x到期之前,新创建的timer不会被GC,到期之后才会GC。
随着时间推移,尤其是duration x很大的话,会产生内存泄露的问题,应特别注意
for true { select { case <-time.After(time.Minute * 3): // do something default: time.Sleep(time.Duration(1) * time.Second) } } 为了保险起见,使用NewTimer()或者NewTicker()代替的方式主动释放资源,两者的区别请自行查阅或看我往期文章https://blog.csdn.net/weixin_38299404/article/details/119352884
timer := time.NewTicker(time.Duration(2) * time.Second) defer timer.Stop() for true { select { case <-timer.C: // do something default: time.Sleep(time.Duration(1) * time.Second) } } 1.2 time.NewTicker资源未及时释放 在使用time.NewTicker时需要手动调用Stop()方法释放资源,否则将会造成永久性的内存泄漏
timer := time.NewTicker(time.Duration(2) * time.Second) // defer timer.Stop() for true { select { case <-timer.C: // do something default: time.
环境:
window 10mysql 8.0.25vs2022.net core 3.1DBeaver 参考:《mysql:11.1.5 Bit-Value Type - BIT》
1. bit(M) 表示位类型,如: create table test(t_bit bit(16))
数据库中存储的是M个bit位,M范围是:[1,64],默认是1。
存储时,将原数据的bit位从右截取M个bit位存储到数据库:
如果原数据bit位长度小于M,则直接补0;如果大于M,截取M长度后,原数据的左侧还有1,则报异常,否则将截取后的bit位直接存储到数据库; 看下面示例:
create table test.test( t_bit bit, t_bit8 bit(8), t_bit16 bit(16), t_bit32 bit(32), t_bit64 bit(64), t_bit4 bit(4) ) insert into test.test(t_bit,t_bit8,t_bit16,t_bit32,t_bit64,t_bit4)values(true,1,2,3,4,5) insert into test.test(t_bit,t_bit8,t_bit16)values(0x01,0xFF,0x0001) insert into test.test(t_bit,t_bit8)values(b'1',b'01010001') -- 查看元数据 select c.TABLE_SCHEMA ,c.TABLE_NAME ,c.COLUMN_NAME ,c.ORDINAL_POSITION,c.DATA_TYPE,c.NUMERIC_PRECISION ,c.COLUMN_TYPE from information_schema.`COLUMNS` c where TABLE_SCHEMA ='test' and TABLE_NAME ='test' order by ORDINAL_POSITION select * from test.
1.复制旧表的数据到新表(假设两个表结构一样) INSERT INTO 新表 SELECT * FROM 旧表
INSERT INTO tbl_user_copy SELECT * FROM tbl_user;
数据量:500万,用时:138.678s(2.3分钟);
删除500万数据用时:142.89s (2.38分钟)
2.复制表结构及数据到新表CREATE TABLE 目标表名 SELECT * FROM 源表名
select * into 目标表名 from 源表名(要求目标表不存在,因为在插入时会自动创建)(备注:该语句不适应于mysql)
语句:CREATE TABLE tbl_user_copy SELECT * FROM tbl_user
数据量:500万 , 用时:113.266s;
3.只复制表结构:
CREATE TABLE 新表
SELECT * FROM 旧表 WHERE 1=2
3.表结构不一样的表备份
INSERT INTO 新表(字段1,字段2,…….)
SELECT 字段1,字段2,…… FROM 旧表
最后 深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
小编已加密:aHR0cHM6Ly9kb2NzLnFxLmNvbS9kb2MvRFVrVm9aSGxQZUVsTlkwUnc==出于安全原因,我们把网站通过base64编码了,大家可以通过base64解码把网址获取下来。
一.Ubuntu系统c语言输出hello world
1.在终端窗口输入vi hello.c创建文件,输入i进入编辑模式开始输入程序,输入完后按esc到命令模式,输入:wq保存并退出。
2.使用gcc编译实行可执行文件
在终端窗口输入gcc hello.c -o hello命令编译hello.c 再输入./hello执行输出
二.Ubuntu系统下便携编写简单的主程序和子程序
1.编写主程序(创建文件和编写过程与hello world类似) 2.编写子程序
3.用gcc命令将主程序和子程序衔接并输出
三.在windows系统下编写简单主程序,子程序 四.Ubuntu系统用makefile方式编程
1.创建并编译makefile规则文件 保存后在终端窗口输入 make执行
使用docker在威联通nas上一键部署jellyfin
直接命令行启动jellyfin,减少前台配置
开启硬件解码,支持自动从TMDB刮削
环境 威联通451D(CPU为J4025,支持硬解)docker 20.10.3jellyfin 10.7.7
部署jellyfin 通过SSH工具登录NAS
查看CPU是否支持硬件解码
ls -l /dev/dri/ # 存在renderD128,并赋予执行权限 # 注意:nas重启后需要重新赋权 sudo chmod 777 /dev/dri/renderD128 部署jellyfin
# 启动jellyfin容器 docker run -d --restart=always \ --name=jellyfin \ -p 32778:8096 -p 32770:8920 \ -v /share/container/jellyfin:/config -v /share/homes/admin/gxf/movie-jellyfin:/media \ --device /dev/dri/renderD128:/dev/dri/renderD128 --device /dev/dri/card0:/dev/dri/card0 \ --add-host api.themoviedb.org:52.84.18.87 \ linuxserver/jellyfin:latest –restart=always:docker重启后会自动启动容器,作用是nas重启后jellyfin会自动启动
-p 32778:8096 -p 32770:8920: 将容器内端口映射到宿主机的端口,其中32778就是访问jellyfin webui的端口
-v /src/dir:/target/dir :挂载本地的目录挂载到容器目录
–device:将宿主机设备添加到容器, --device /dev/dri:/dev/dri 也是可以的
–add-host:由于某些网络问题,刮削非常慢或者更本无法下载,可通过修改host,指定api.themoviedb.org解析到可用的IP。将13.225.97.51 api.themoviedb.org写入到容器的/etc/hosts文件中,使用TMDB支持海报和资料的刮削。具体网址可以到dnschecker上查找。
# 查看成功启动jellyfin docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7454b235aceb linuxserver/jellyfin:latest "
数据 输入特征可以根据实际情况进行选择,这里选择的输入为[“收盘价”,“最高价”,“最低价”],对未来的收盘价进行预测。
数据处理 def preprocess_data(data, time_len, rate, seq_len, pre_len): train_size = int(time_len * rate) train_data = data[0:train_size] test_data = data[int(time_len*(rate)):time_len] trainX, trainY, valX,valY,testX, testY = [], [], [], [],[],[] for i in range(len(train_data) - seq_len - pre_len+1): a = train_data[i: i + seq_len + pre_len] trainX.append(a[0: seq_len]) trainY.append(a[seq_len: seq_len + pre_len]) for i in range(len(test_data) - seq_len - pre_len+1): b = test_data[i: i + seq_len + pre_len] testX.append(b[0: seq_len]) testY.
QoS0:最多发送一次,到达不到达发布者不管,发布者(客户端,服务端做为发送端的时候)只发送一次,不管接收端是否收到数据;
QoS1:至少到达一次,发布者需要到达后有确认,发布者(客户端,服务端做为发送端的时候)发布消息后等待接收者(客户端,服务端做为接收端的时候)的确认信息报文;如果发布都没有收到确认报文,发布者会一直发送消息;
QoS2:只有一次到达,发布者需要到达后确认,接收者需要发布者再次确
按照介绍的MQTT消息的三个等级如上所示,
按照我之前的理解是如果消息等级是1 ,那么至少应该有一个客户端能收到消息。
但是这里需要注意的是如果消息发送时,没有任何订阅客户端连接到Mqtt 服务器,那么无论你的消息等级有多高,新连接的订阅客户端是不会收到这条消息的。
具体的场景是:
(1)我发送了一条qos=1的消息,然后我启动了一个订阅客户端,这时我的订阅客户端是收不到消息的。
(2)为了能收到qos=1的消息,订阅客户端需要使用固定clientid登陆mqtt 服务器,并且订阅某个主题,这时如果订阅客户端断线,断线期间有消息发送,那么订阅客户端在重连之后是可以收到消息的。
下面用python paho-mqtt举例
#发送端 设置消息级别是1 mqttclient.publish("topic1", payload="hello world", qos=1) #clean_session=False 是需要设置的参数,表示客户端是一个永久性客户端,短线 #重连后,可以收到错过的消息 scribeclient = mqtt.Client(client_id="clientid11111", clean_session=False) #连接后订阅的级别同样需要有参数qos=1 self.client.publish(topic, payload=msg, qos=1)
简介 本篇读完需要10分钟,读完能了解:
TCP4次挥手
为什么要4次挥手
TIME_WAIT等待2MSL的原因
TCP故障检测
相关阅读 目录
断开连接过程(4次挥手) TIPS 三次挥手会有什么问题
B向A发送链接释放报文(FIN=1,ACK=1)后直接断开连接,如果A没有收到这个FIN数据包,A就会一直处于FINT-WAIT-2状态
等待2MSL(最大报文段生存时间)原因
网络不可靠的情况,会出现最后一个ACK丢失。B如果没有收到ACK,将不断重复发送FIN片段。A会设置一个计时器,等待2MSL的时间。如果在该时间内再次收到FIN,那么A会重发ACK并再次等待2MSL。2MSL就是一个发送和一个回复所需的最大时间。如果直到2MSL,Client都没有再次收到FIN,那么Client推断ACK已经被成功接收,则结束TCP连接。
如果已经建立了连接,但是客户端突然出现故障了怎么办?
TCP还设有一个keepalive计时器,服务器每收到一次客户端的请求后都会重新Reset这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。
TIME_WAIT扩展 场景: 在高并发短连接的TCP服务器上,当服务器处理完请求后立刻主动正常关闭连接。这个场景下会出现大量socket处于TIME_WAIT状态。如果客户端的并发量持续很高,此时部分客户端就会显示连接不上。
查询现象: netstat -ant|awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print (a,S[a])}’
LAST_ACK 14
SYN_RECV 348
ESTABLISHED 70
FIN_WAIT1 229
FIN_WAIT2 30
CLOSING 33
TIME_WAIT 18122
处理: 编辑内核文件/etc/sysctl.conf,加入以下内容: net.ipv4.tcp_syncookies = 1 表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭;
net.ipv4.tcp_tw_reuse = 1 表示开启重用。允许将TIME-WAIT
sockets重新用于新的TCP连接,默认为0,表示关闭; net.ipv4.tcp_tw_recycle = 1
表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭。 net.ipv4.tcp_fin_timeout
修改系默认的 TIMEOUT 时间 然后执行 /sbin/sysctl -p 让参数生效.
1 ViewModel简介 Android平台上之所以会出现诸如MVP、MVVM之类的项目架构,就是因为在传统的开发模式下,Activity的任务实在是太重 了,既要负责逻辑处理,又要控制UI展示,甚至还得处理网络回调,等等。在一个小型项目中这样写或许没有什么问题,但是如果在大型项目中仍然使用这种写法的话,那么这个项目将会变得非常臃肿并且难以维护,因为没有任何架构上的划分。
以下是ViewModel的官网介绍:The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way. The ViewModel class allows data to survive configuration changes such as screen rotations.
ViewModel类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel类让数据可在发生屏幕旋转等配置更改后继续留存。
**ViewModel的作用是存放和界面相关的数据,分担Activity/Fragment的一部分工作,同时维护自己独立的生命周期。**也就是说,只要是界面上能看得到的数据,它的相关变量都应该存放在ViewModel中,这样可以在一定程度上减少Activity中的逻辑。
**另外,Activity/Fragment经常需要处理一些异步调用,要管理这些调用,并确保在其销毁后清理这些调用以避免潜在的内存泄漏。**此项管理需要大量的维护工作,并且在为配置更改重新创建对象的情况下,会造成资源的浪费,因为对象可能需要重新发出已经发出过的调用。
**还有就是当系统配置发生变化(如切换语言)或者横竖屏切换时,导致Activity销毁重建,与界面相关的数据都会丢失。**对于简单的数据,Activity可以使用 onSaveInstanceState() 方法从 onCreate() 中的捆绑包恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。这个时候就可以使用ViewModel来解决问题。
2 ViewModel的生命周期 下图说明了Activity经历屏幕旋转而后结束时所处的各种生命周期状态,该图还在关联的Activity生命周期的旁边显示了ViewModel的生命周期。此图说明了Activity的各种状态,这些基本状态同样适用于Fragment的生命周期。
ViewModel的生命周期方法只有一个onCleared(),在ViewModel实例被清除的时候回调。
ViewModel实例存在的时间范围是:获取ViewModel实例时传递给ViewModelProvider的Lifecycle。ViewModel将一直留在内存中,直到限定其存在时间范围的Lifecycle永久消失:对于activity,是在activity完成时;而对于fragment,是在fragment分离时。
ViewModelProvider(<Activity或Fragment实例>).get(<定义的ViewModel>::class.java) 通常在系统首次调用Activity对象的 onCreate() 方法时请求ViewModel。系统可能会在activity的整个生命周期内多次调用 onCreate(),如在旋转设备屏幕时。因此,这里没有使用new来创建ViewModel实例。
另外,当手机发生横竖屏旋转的时候, Activity会被重新创建,同时存放在Activity中的数据也会丢失。**而ViewModel和Activity不同, 它可以保证在手机屏幕发生旋转的时候不会被重新创建,只有当Activity退出的时候才会跟着Activity一起销毁。**因此,将与界面相关的变量存放在ViewModel当中, 这样即使旋转手机屏幕,界面上显示的数据也不会丢失。
3 ViewModel的基本用法 第一步:添加依赖 由于Jetpack中的组件通常是以AndroidX库的形式发布的,因此一些常用的Jetpack组件会在创建Android项目时自动被包含进去。 不过如果想要使用ViewModel组件,还需要在app/build.gradle文件中添加如下依赖:
dependencies { .... implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" } 第二步:创建ViewModel 通常来讲,比较好的编程规范是给每一个Activity和Fragment都创建一个对应的ViewModel,因此这里为TimerActivity创建一个对应的TimerViewModel类,并让它继承自ViewModel,代码如下所示:
class TimerViewModel: ViewModel() { } 根据前面所学,所有与界面相关的数据都应该放在ViewModel中。要实现 一个计数器的功能,就可以在ViewModel中加入一个counter变量用于计数,如下所示:
默认已在vs中配置好c++环境。
参考链接:创建窗口 - LearnOpenGL CN
环境配置文件:
文件名:opengl
链接:https://pan.baidu.com/s/1KN4cjFn5fhGSJ9ZGRuM5fA 提取码:1121
#########################################################################
1 建立c++空项目,将debug的下拉列表从x86改为x64。
图1
2 在项目点击右键,进入属性。在VC++目录和链接器中的输入分别进行以下修改(修改完为粗黑体)。
2.1把包含目录和库目录分别改成如下:
图2—1 2.2 对附加依赖项,手打改成如下图的粗黑体字(两个lib文件)
图2—2 3 在项目中添加现有项,glad.c
图3—1 4 输入以下代码,按下F5,没有报错就说明安装成功了。
#include <glad/glad.h> #include <GLFW/glfw3.h>
目录 一、快速入门1. 安装2.配置镜像加速 二、常用命令0. 预备1.镜像命令1.1 查看所有本地主机的镜像1.2 搜索镜像1.3 下载镜像1.4 删除镜像 2.容器命令2.1 启动容器:2.2 查看容器:2.3 删除容器:2.4 启动和停止容器: 3.其他命令3.1 后台启动:3.2 查看日志:3.3 查看容器中的进程信息:3.4 查看镜像的元数据:3.5 进入当前正在运行的容器3.6 从容器内拷贝文件到主机上 4.练习4.1 部署Nginx4.2 部署Tomcat4.3 部署 es + kibana 三、可视化工具1. portainer2. Rancher(CI/CD) 四、Docker镜像1. 镜像是什么?2. Docker镜像加载原理2.1 UnionFs (联合文件系统)2.2 Docker镜像加载原理 3.分层理解4. commit镜像 五、容器数据卷1. 什么是容器数据卷?2. 使用容器数据卷3. 实战:安装MySQL4. 具名和匿名挂载4.1 匿名挂载4.2 具名挂载(推荐) 5. 初识Dockerfile6. 数据卷容器7. Dockerfile7.1 构建步骤7.2 Dockerfile构建过程7.2.1 基础知识:7.2.2 Dockerfile的指令7.2.3 实战测试7.2.4 CMD 和 ENTRYPOINT7.2.5 实战-Tomcat镜像7.2.6 发布自己的镜像7.2.7 发布到阿里云镜像服务上 8. Docker小结: 六、Docker网络1、理解Docker02、- - Link3、自定义网络4、部署Redis集群 七、SpringBoot微服务打包Docker镜像八、DockerCompose1、简介2、安装3、体验4、yaml规则5、实战开源项目6、实战 九、DockerSwarm1、集群2、Raft协议3、体会4、概念总结 十、Docker Stack十一、Docker Secret十二、Docker Config 一、快速入门 1.
目录
一、什么是RBAC模型?
二、RBAC的权限授权过程
三、 RBAC模型中的核心概念
四、RBAC支持三个著名的安全原则:
最小权限原则、责任分离原则和数据抽象原则
一、什么是RBAC模型? RBAC模型(Role-Based Access Control:基于角色的访问控制)模型
是20世纪90年代研究出来的一种新模型,但其实在20世纪70年代的多用户计算时期,这种思想就已经被提出来,直到20世纪90年代中后期,RBAC才在研究团体中得到一些重视,并先后提出了许多类型的RBAC模型。其中以美国George Mason大学信息安全技术实验室(LIST)提出的RBAC96模型最具有代表,并得到了普遍的公认。
在RBAC模型里面,有3个基础组成部分,分别是︰用户、角色和权限。
RBAC通过定义角色的权限,并对用户授予某个角色从而来控制用户的权限,实现了用户和权限的逻辑分离(区别于ACL模型),极大地方便了权限的管理。
二、RBAC的权限授权过程 RBAC认为权限授权的过程可以抽象地概括为:
Who是否可以对What进行How的访问操作,并对这个逻辑表达式进行判断是否为True的求解过程,也即是将权限问题转换为What、How的问题,Who、What、How构成了访问权限三元组,具体的理论可以参考RBAC96的论文,这里我们就不做详细的展开介绍,大家有个印象即可。
三、 RBAC模型中的核心概念 RBAC模型中的核心概念包括:
- User(用户)︰每个用户都有唯一的UID识别,并被授予不同的角色
- Role (角色)︰不同角色具有不同的权限
- Permission(权限)︰访问权限
-用户-角色映射:用户和角色之间的映射关系
-角色-权限映射:角色和权限之间的映射
四、RBAC支持三个著名的安全原则: 最小权限原则、责任分离原则和数据抽象原则 最小权限原则:RBAC可以将角色配置成其完成任务所需的最小权限集合责任分离原则:可以通过调用相互独立互斥的角色来共同完成敏感的任务,例如要求一个计账员和财务管理员共同参与统一过账操作数据抽象原则:可以通过权限的抽象来体现,例如财务操作用借款、存款等抽象权限,而不是使用典型的读、写、执行权限
想必同学们已经开学了,也都进入了军训阶段吧,而很多计算机网络专业的同学们要开始接触到Windows Server了,这也是计算机网络技术专业的专业基础课程,想当年我们实训课学习使用的好像是2008版的,也不晓得现在各个学校会用到哪个版本实操,盲猜应该是2012版,哈哈。
言归正传,那么Windows Server和我们平时使用的Windows XP、Windows7、Windows10以及Windows11有什么区别呢。首先,他是微软研发的服务器操作系统,相比于我们的个人PC也就是Windows7、10等之类的操作系统来说,他的处理能力、I/O性能、管理能力、可靠性以及扩展性更强,若要配置网络服务器,他是可选之一。
下图是为各位同学整理好的Windows Server各个版本的微软原版镜像文件,可供同学们学习使用,之后也会在后文中附上微软官方链接,以及整理好的文件的链接。
Windows Server 版本 一、版本功能 官方版本功能比较:https://docs.microsoft.com/zh-cn/windows-server/get-started/editions-comparison-windows-server-2016
**警告!警告!下面几张图内容较多,和官方的一样,想要了解的可以看看,否则可以直接跳过,哈哈
通常可用的功能版本区别 锁定和限制版本区别 可用的角色版本区别 可用功能版本区别 二、硬件要求 微软官方详细回答:https://docs.microsoft.com/zh-cn/windows-server/get-started/hardware-requirements 整理精简回答:
处理器:1.4 GHz 64 位处理器,与 x64 指令集兼容
内存(RAM):800 MB(对于带桌面体验的服务器安装选项为 2 GB)
磁盘存储空间:32 GB
网络适配器:以太网适配器的吞吐量至少为 1 GB/秒、符合 PCI Express 体系结构规范
三、准备工作 ①VMware Workstation软件
(演示版本:vmware-workstation-full-16.2.1-18811642exe)
【下载链接】http://ai95.microsoft-cloud.cn/d/9289114-49833935-3c06d9?p=ai95 (访问密码:ai95)长期更新
VMware Workstation 虚拟机软件 ②Windows Server 2016系统原版镜像文件包
(演示版本:cn_windows_server_2016_vl_x64_dvd_11636695.iso)
【下载链接】http://ai95.microsoft-cloud.cn/d/9289114-49837643-63668d?p=ai95 (访问密码:ai95)长期更新
Windows Server 操作系统 四、虚拟机配置 我们准备工作若是完成了,接下来就开始配置虚拟机了
4.1 新建虚拟机
4.1 新建虚拟机向导 4.2 选择虚拟机的【兼容性】(一般都是根据虚拟机版本默认选择最新的兼容性)
4.2 虚拟机硬件兼容性 4.3 选择【稍后安装操作系统】
(若是此选项直接插入光盘,可能会要求属于密钥,无法进行下一步学习)
马上就要开学了,想必很多计算机网络专业的同学们要开始接触到Windows Server了,这也是计算机网络技术专业的专业基础课程,想当年我们实训课学习使用的好像是2008版的,也不晓得现在各个学校会用到哪个版本实操,盲猜应该是2012版,哈哈。
言归正传,那么Windows Server和我们平时使用的Windows XP、Windows7、Windows10以及Windows11有什么区别呢。首先,他是微软研发的服务器操作系统,相比于我们的个人PC也就是Windows7、10等之类的操作系统来说,他的处理能力、I/O性能、管理能力、可靠性以及扩展性更强,若要配置网络服务器,他是可选之一。
下图是为各位同学整理好的Windows Server各个版本的微软原版镜像文件,可供同学们学习使用,之后也会在后文中附上微软官方链接,以及整理好的文件的链接。
Windows Server 版本 一、版本功能 我们来看看这个新版本的官方回答吧:
Windows Server 2022是微软研发的服务器操作系统,在2021年公开测试并发布。在Windows Server 2019的基础上有许多的创新设计:高层多级安全性、Azure混合功能和灵活的应用程序平台。Windows Server 2022分为带有GUI桌面和不带GUI桌面的命令行版本。按照不同用户区分的话,Windows Server 2022有针对个人或普通用户发售的零售版本,也有能提供长时间技术支持更新服务的Windows Server 2022 LTSC企业用户版本。
目前微软已经发布了Windows Server 2022 Standard、Datacenter和Datacenter Azure三种版本。在这三个版本中Windows Server 2022 Standard(标准版)是主要版本。下面将为你介绍Windows Server 2022安装的全部过程。
官方版本功能比较:https://docs.microsoft.com/zh-cn/windows-server/get-started/editions-comparison-windows-server-2022
**警告!警告!下面几张图内容较多,和官方的一样,想要了解的可以看看,否则可以直接跳过,哈哈
通常可用的功能版本区别 锁定和限制版本区别 可用的角色版本区别 可用功能版本区别 二、硬件要求 微软官方详细回答:https://docs.microsoft.com/zh-cn/windows-server/get-started/hardware-requirements
整理精简回答:
处理器:1.4 GHz 64 位处理器,与 x64 指令集兼容
内存(RAM):800 MB(对于带桌面体验的服务器安装选项为 2 GB)
磁盘存储空间:32 GB
网络适配器:以太网适配器的吞吐量至少为 1 GB/秒、符合 PCI Express 体系结构规范
三、准备工作 ①VMware Workstation软件
(演示版本:vmware-workstation-full-16.2.1-18811642exe)
【下载链接】http://ai95.microsoft-cloud.cn/d/9289114-49833935-3c06d9?p=ai95 (访问密码:ai95)长期更新 VMware Workstation 虚拟机软件 ②Windows Server 2022系统原版镜像文件包