经典卷积模型回顾25—利用蒸馏对DenseNet201进行处理,并实现图像分类(matlab)

模型蒸馏的具体意思是,从一个大型深度学习模型中抽取(transfers)小型模型来实现对技术的迁移。模型蒸馏的过程很像重新利用和重新学习知识,它能够帮助改善不同模型之间的性能,从而获得高度精准的预测结果。 代码如下: %定义变量 net = densenet201();%使用densenet201模型来定义网络 imgDir = 'F:\测试图片路径'%存放测试图片的路径 batchSize = 32;%设置mini batch大小 %使用模型蒸馏将原始模型中掩码量进行处理 distilledNet = distill(net,'softmax'); %通过ImageDatastore函数从imgDir路径读取所有图片数据 imds = imageDatastore(imgDir); %在densenet201模型上定义一个分类器 classifier = trainNetwork(imds, distilledNet, 'MiniBatchSize', batchSize); %我们还可以使用其他机器学习算法(如svm、knn等)也可以对此结果进行训练 %测试:存放待测试图片的文件夹路径 testImgDir = 'F:\测试图片文件夹路径'; %从 testImgDir路径读取所有待测试照片 imdsTest = imageDatastore(testImgDir); %使用densenet201模型的蒸馏版本进行图像分类,并输出预测标签 preLabel = classify(classifier,imdsTest); %打印输出结果 disp('模型预测结果:'); disp(preLabel);

用NetCore手撸RTSP交互协议

注意点 1. DESCRIBE 第1次发送时返回401错误,返回信息带 realm,nonce,参数使用MD5校验后重新发送; 2. SETUP 的url信息,由DESCRIBE返回的head中的sdp字符串中解析,readonly,x-dimensions(视频分辨率),control(视频url),rtpmap(编解码信息) 3.PLAY的Session信息,由SETUP返回的head中的Session 4.解析完后,tcpclient接收rtp数据包,可用ffmepg进行解码 核心代码RTSPClient.cs using System.Net.Sockets; using System.Text; namespace RtspClientCore { class RtspClient { string rtspUrl = "rtsp://192.168.0.2:554/h264/ch1/main/av_stream"; string username = "admin"; string password = "thzn123456"; TcpClient tcpClient; NetworkStream tcpStream; private int cseq; public Uri rtspUri { get; set; } public int NewCSeq { get { return ++cseq; } } string Authorization = ""; string Session = ""; string UserAgent = "C# RTSP Client"

Python如何打包exe文件? 如何换成喜欢的图标?

要将Python脚本打包为可执行的exe文件,可以使用第三方库pyinstaller。以下是将Python脚本打包为可执行exe文件的步骤: 1.安装pyinstaller:在命令行中使用以下命令安装pyinstaller: pip install pyinstaller 2.切换到包含Python脚本的目录。 3.在命令行中使用以下命令打包你的脚本: pyinstaller your_script_name.py 4.如果打包成功,则你的exe文件将在dist文件夹中。 如果想要将exe文件的图标更改为你喜欢的图标,请按照以下步骤操作: 创建一个ICO格式的图标文件并将其命名为icon.ico。 使用以下命令重新打包exe文件: pyinstaller --onefile --icon=icon.ico your_script_name.py 请注意,必须将图标文件放在与你的Python脚本相同的目录中。执行此命令后,将生成包含所选图标的单个可执行文件。

电磁波的极化表征-3-Stocks矢量和Poincare球

这一章咱们谈谈Stocks和Poincare球 极化波不仅包含完全极化电磁波,即电场矢量的端点在时变的极化椭圆上做周期性运动,还包含其他两种方式:部分极化波和非极化波。而琼斯矢量只适合于描述完全极化波,对于部分极化波,需要引入新的描述方法对其进行表征。 注:文章摘选自《合成孔径雷达图像解译与应用技术》孙洪等著

pycharm连接服务器

注意:一定要使用专业版pycharm 说明:主要有两种方法 连接服务器和使用pycharm debug 打开pycharm专业版 test Connection成功后直接apply 注意:如果不需要debug,直接到下一章节终端 选择刚刚连接的服务器sshserver 下面直接create 修改上传代码方式(可选) 一直就是自动上传,这里最好选择保存后上传。 下面就可以直接运行代码和debug了。 命令行 打开一个终端 命令行运行程序:python + 文件名(注意:先到指定虚拟环境下, 并cd到项目文件夹里) 常见命令: cd /home 进入home目录 cd …返回上一级目录 pwd 显示工作路径 source ~/.bashrc 刷新环境变量 conda常见命令 获取版本号/帮助 获取版本号 conda -V conda --version 获取帮助 conda -h conda --help 获取环境相关命令的帮助 conda env -h 所有 --单词 都可以用 -单词首字母来代替 比如 -version 可以用 -V来代替,只不过有的是大写,有的可能是小写环境相关 创建环境 conda create -n environment_name 创建指定python版本下包含某些包的环境 conda create -n environment_name python=3.7 numpy scipy 进入环境 conda activate environment_name

常见grep,sed,awk命令

1.grep查找 结合正则表达式功能十分强大 grep [选项] 要查找内容(可用正则表达式) 在该文件中查找 常用选项: -c 只显示匹配的行数 -h 查询多文件时不显示文件名 -I 不区分大小写 -l 查询多文件时,只输出匹配文件的文件名 -n 显示匹配的行及行号 -v 显示不包含匹配文本的所有行 2.sed编辑 三种使用方法: 1、在shell命令行调用 格式:sed [选项] ‘command’ 输入文件 command要加单引号,也允许加双引号 2、将sed命令插入脚本后,通过sed命令调用 格式:sed [选项] -f sed脚本文件 输入文件 3、将sed命令插入脚本后,执行该脚本 格式:./sed脚本文件 输入文件 常用选项: -e 多重编辑 -i 直接编辑,修改文件内容 -f -n 安静模式,只显示处理的那一行,而不显示来自stdin输入的内容 动作: a 新增至下一行,a后面接字符串 c 取代 sed '/test/c RRRR' test.txt d 删除 i 插入至上一行,i后面接字符串 p 打印 s 取代 3.awk文本分析并处理 相对于sed常常用于处理一行,awk更倾向于处理一行中的一个一个字段 3.1 三种使用方式 1、在shell命令行调用 格式:awk [-F 域分隔符] ‘command’ 输入文件 2、将awk命令插入脚本后,通过awk命令调用 格式:awk -f awk脚本文件 输入文件 3、将awk命令插入脚本后,执行该脚本 #!

adb logcat 常用参数

1.显示全部日志 adb logcat 2.筛选日志 adb logcat -s [TAG] [TAG] [TAG] [TAG]... 筛选是TAG的日志 adb logcat | grep [TAG] 筛选以TAG开头的日志 adb logcat [TAG]:S 过滤掉是TAG的日志 adb logcat -b crash 查看日志中出现的crash 3.保存日志到文件 adb logcat > ~/Desktop/log.txt adb logcat -v time > ./a.log 日志输出到文件,-v表示输出格式 adb logcat -v time | tee ./a.log 日志输出到文件和屏幕 -d 将日志显示在控制台后退出 -c 清理已存在的日志 -f <filename> 将日志输出到文件 -v <format>设置日志输入格式控制输出字段,默认的是brief格式 brief — 显示优先级/标记和原始进程的PID (默认格式) process — 仅显示进程PID tag — 仅显示优先级/标记 thread — 仅显示进程:线程和优先级/标记 raw — 显示原始的日志信息,没有其他的元数据字段 time — 显示日期,调用时间,优先级/标记,PID long —显示所有的元数据字段并且用空行分隔消息内容 注意-v 选项中只能指定一种格式

Android常见SWT/ANR原因

文章目录 一、为什么需要SWT二、常见问题类型三、常见SWT/ANR原因有如下几种1.等锁2. SurfaceFlinger卡住3.Native方法执行时间过长4. Binder Server卡住5. Zygote fork进程时卡住6. Dump时间过长 一、为什么需要SWT System Server进程是Android的一个核心进程,里面为APP运行提供了核心的服务。如果System Server的一些核心服务和重要线程卡住,就会导致相应的功能异常。 如手机发生hang机,输入无响应,无法启动APP等一些不正常的情况。而且,如果没有一种机制,让这些服务复位的话,那么将严重影响客户体验。尤其是当前大多数手机把电池封装在手机里面的这种,想拨电池重启都很难。 所以有必要在核心服务和核心线程卡住的时候,让系统有自动复位的机会。于是,google引入了Sytem Server watchdog机制。这个机制来监控核心服务和核心线程是否卡住。 二、常见问题类型 根据问题的历史数据,整理了SWT/ANR常见的问题类型。 SWT主要分Blocked和非Blocked类型,这两大类又进行了模块层面的细化,并从trace和现象上给予一定的问题描述。 ANR主要分性能和非性能类型。 三、常见SWT/ANR原因有如下几种 1.等锁 线程状态为“Blocked”,通过关键字“held by”进一步确认哪个线程拿住了锁,如有死锁检查code逻辑进行解锁; 线程状态为“Waiting”,表示当前线程需要另外一个线程来notify(),需要根据callstack结合code来做分析,以找到是另外的某个线程拿住了锁。 如果很多线程在等同一把锁,可能产生资源竞争问题,导致某些线程可能拿不到锁。 2. SurfaceFlinger卡住 SF hang Time > 40s(Service.sf.status值),sf hang, 直接在”SYS_ANDROID_LOG”搜索”I watchdog”,看是否有“surfaceflinger hang”关键字。 如果有,请进一步确认main_log里有"SF-WD"相关log打印, 或者与SWT相关的thread block在android.view.SurfaceControl.XXXX,更进一步分析请参考如下链接内容: Quick Start > SurfaceFlinger Hang issue Guide 3.Native方法执行时间过长 线程状态为”Native”,根据native方法找到对应模块的owner,进一步确认该native方法为何执行时间过长,例如是否等待硬件返回或者硬件本身存在问题等。 4. Binder Server卡住 线程状态为“Native”,且含有如下callstack: IPCThreadState::waitForResponse–>IPCThreadState::talkWithDriver, 表示卡在binder对端,下一步要找到对端,找到对端后,从对端thread的callstack中确认卡住的接口,并请对端相关的owner帮忙解决。 怎么寻找binder对端信息? a. 根据binder thread的sysTid在SYS_BINDER_INFO/SWT_JBT_TRACES/ kernel_log中查找binder通信对端,关键字“outgoing transaction” b.在SYS_PROCESSES_AND_THREADS通过对端的sysTid查找process name c. 如果对端是Monkey,比较特别,可以不用关注,除非是严重影响Monkey Test。 d. 上述方法找不到binder对端,请参考“[FAQ22212] 如何根据binder client端查找binder server端?”

dedecms织梦首页被篡改 网站被黑被跳转的解决办法建议

2018年的中秋节即将来临,我们最近接到很多用dedecms程序的企业公司网站客户的反馈,说是公司网站经常被篡改,包括网站首页的标题内容以及描述内容,都被改成了什么北京sai车,北京PK10等等的caipiao内容,而且大多数的网站客户都是从百度搜索关键词,点击进公司网站会被直接跳转到dubo网站上去。 对此我们已经处理过很多像这样问题的客户网站,这种安全问题普遍的特征就是:频繁反复性质的篡改网站首页,重新在网站后台首页生成后,被篡改的内容就会清除,但没过多久就又被篡改了,使很多网站的负责人很烦恼,公司网站频繁被黑被篡改被跳转dubo,caipiao网站的安全问题,给公司的利益带来了很大的损失,比如客户从百度搜索公司产品或百度推广的地址进入到公司网站会被直接跳转到duboi、caipiao网站上去,导致客户对该公司的信誉大大降低,产生不信任。下面把我们如何解决客户网站跳转的过程,以及如何做好网站的安全部署,记录一下,希望能帮到更多出现网站被跳转的客户。 综合以上客户网站情况以及网站被黑的症状,我们工程师立即对该公司网站dedecms的程序代码进行了详细的代码安全审计,以及隐蔽的网站木马后门进行了清理,包括对网站漏洞修复,进行了全面的网站安全部署,对网站静态目录进行了PHP脚本权限执行限制,对dedecms的覆盖变量漏洞进行了修补,以及上传文件绕过漏洞和dedecms的广告文件js调用漏洞进行了深入的修复过滤了非法内容提交,清除了多个脚本木马文件,并对网站默认的后台地址进行了更改,以及dedecms注入漏洞获取到管理员的user和password值,对此我们对dedecms的漏洞修复是全面化的人工代码审计以及修复漏洞代码,因为用dedecms做企业网站排名和优化访问速度比较快。所以如果想要优化和访问速度快又想网站安全建议大家做下网站全面的安全加固服务. 2.dedecms织梦首页被篡改,网站被黑,被跳转的解决办法建议: 对后台默认登录地址如dede改为其他名称,管理员账户和密码一定要复杂点。 如果对程序代码不熟悉的话建议咨询网站安全公司或者网站漏洞修复公司。 对静态目录文件进行脚本权限限制。 加强对网站sql注入防护的措施过滤。 没用的插件以及会员系统可以直接关闭或删除。 升级dedecms,织梦系统的版本到最新版本。

Android分辨率适配

Android设备的分辨率各不相同,因此在开发Android应用程序时需要进行分辨率适配。以下是一些常用的方法: 使用相对单位:在设计布局时,使用相对单位如dp(density-independent pixels)和sp(scaled pixels)而不是像素(px)。这可以确保布局在不同分辨率的设备上看起来相似。 使用限制符:Android提供了限制符来帮助开发人员根据不同的设备配置提供不同的资源。例如,可以创建不同分辨率下的布局文件,将它们放置在不同的文件夹中,以确保在不同的设备上使用正确的布局。 缩放位图:使用缩放位图可以确保图像在不同分辨率的设备上都以适当的尺寸呈现。在Android开发中,可以将图像放在不同的文件夹中,以确保在不同的设备上使用正确的图像。 动态布局:使用代码编写动态布局,可以确保布局在不同分辨率的设备上以适当的比例进行缩放。这可以通过计算屏幕宽度和高度,并相应地调整布局来实现。 综上所述,通过使用相对单位、限制符、缩放位图和动态布局等方法,可以在开发Android应用程序时进行分辨率适配。

VRF(虚拟路由转发)

有些地方为了省钱,把两个部门的pc都接在同一个路由器上,但是为了防止两个部门间相互访问,需要做静态路由转发(这是种low的方法): pc1、(gi0/1、gi0/2)、路由器1、运营商1。 pc2、(gi0/3、gi0/4)、路由器2、运营商2。 如下图: 这样很麻烦,用VPF就可以解决这种问题。 我们在R1上创建两个VRF:VRF1及VRF2,创建完成后,我们可以理解为,拥有了两台虚拟路由器。当然,现在这两台虚拟路由器上啥也没有。 接下去我们将GE0/0/1口及GE0/0/2口绑定到VRF1;将GE0/0/3及GE0/0/4口绑定到VRF2。如此一来这两台虚拟路由器就各自拥有了两个物理接口。 值得注意的是,这两台虚拟路由器是虽然都在同一台物理设备上,但是却是隔离的,他们将有自己的接口,自己的路由表,自己的ARP表等等相关的内容。 意:添加到vrf的接口必须是三层接口! VRP之间是相互独立的互不干扰! 把三层接口gi0/1和gi0/2添加到vrf之后,路由表中就会自动把gi0/1和gi0/2的路由信息删除了。 ospf要广播到VRF1,路由器1也要OSPF到VRF1。 锐捷设置流程 大路由器,举例 1.gi0/1-2设置成三层模式。 2.开启mpls ip,创建vrf:ip vrf AA。 3.gi0/1-2进入后ip vrf for... AA,设置ip. 4.route ospf 1 vrf AA,把gi0/1-2广播出去。

02MySQL 日志系统:一条SQL 更新语句是如何执行的?

文章目录 前言1. 更新语句的执行流程1.1 重要的日志模块:redo log1.1.1 举例说明1.1.2 redo log 日志1.1.2.1 InnoDB 的 redo log 大小 1.2 重要的日志模块:binlog1.2.1 为什么会有两份日志呢?1.2.1.1 两种日志有什么不同? 1.2.2 执行器和 InnoDB 引擎在执行update 语句时的内部流程 1.3 两阶段提交1.3.1 为什么日志需要两阶段提交? 2 . 总结2.1 redo log 都直接持久化到磁盘 参数设置2.2 binlog 直接持久化到磁盘 3. 思考3.1 什么场景下,一天一备会比一周一备更有优势呢?或者说,它影响了这个数据库系统的哪个指标?3.2 前言 前面我们系统了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块。相信你还记得,一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后到达存储引擎。那么,一条更新语句的执行流程又是怎样的呢?【mysql8.0之后删除了查询缓存模块】 那么,一条更新语句的执行流程又是怎样的呢? 1. 更新语句的执行流程 之前你可能经常听 DBA 同事说,MySQL 可以恢复到半个月内任意一秒的状态,惊叹的同时,你是不是心中也会不免会好奇,这是怎样做到的呢? 我们还是从一个表的一条更新语句说起,下面是这个表的创建语句,这个表有一个主键 ID 和一个整型字段 c: mysql> create table T(ID int primary key, c int); 如果要将 ID=2 这一行的值加 1,SQL 语句就会这么写: mysql> update T set c=c+1 where ID=2; 前面我有跟你介绍过 SQL 语句基本的执行链路,这里我再把那张图拿过来,你也可以先简单看看这个图回顾下。首先,可以确定的说,查询语句的那一套流程,更新语句也是同样会走一遍。

极化回波矩阵-1-散射矩阵和散射矢量

描述雷达收、发波的传播过程可以用前向散射坐标系,也可以用后向散射坐标系。考虑到单站雷达的雷达入射和目标散射电磁波在后向散射坐标中可以用相同的极化基描述,下面采用后向散射坐标系来讨论散射波的极化特性。 注:文章摘选自《合成孔径雷达图像信息解译与应用技术》孙洪等著

Java底层原理——HashMap底层原理(JDK1.8)

从1.7中可知HashMap是数组+链表的结构,HashMap在JDK1.8中加入了红黑树的实现,当链表长度大于8时,转换为红黑树的结构。 java8中没有indexFor函数,而是直接使用table[index=(n-1)&hash] 在JDK1.8中也使用了取代Entry的Node来实现Map.Entry接口 static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; Node(int hash, K key, V value, Node<K,V> next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } Node是一个内部类,实现了Map.Entry接口,本质就是一个键值对。 HashMap类中有一个非常重要的字段,就是Node[] table,即哈希桶数组,很明显它是一个Node的数组。 如果哈希桶数组很大,即使较差的Hash算法也会比较分散,如果哈希桶数组很小,即使好的Hash算法也会出现较多碰撞,所以就需要在空间成本和时间成本之间权衡,其实就是根据实际情况确定哈希桶数组的大小,并在此基础上设计好的hash算法减少Hash碰撞。主要就是通过好的Hash算法和扩容机制优化HashMap的Node数组。 同样有几个重要字段 int threshold; // 所能容纳的key-value对极限 final float loadFactor; // 负载因子 int modCount; int size; loadFactor参数 首先Node[] table的初始化长度length(默认值时16),loadFactor为负载因子(默认值问0.75),threshold时HashMap所能容纳的最大数据量的Node(键值对)个数。threshold = length * loadFactor。也就是说,在数组定义好长度之后,负载因子越大,所能容纳的键值对个数越多。 threshold参数 结合负载因子的定义公式可知,threshold就是就是在此loadFactor和length(数组长度)对应下允许的最大元素数目,超过这个数目就得重新resize(扩容),扩容后的HashMap容量是之前容量的两倍。默认的负载因子0.75是对空间和时间效率的一个平衡选择,除非在时间和空间比较特殊的情况下,如果内存空间很多而又对时间效率要求很高,可以降低负载因子loadFactor的值;相反,如果内存空间紧张而对时间效率要求不高,可以增加负载因子loadFactor的值,这个值可以大于1。 size参数 这个参数很好理解,就是HashMap中实际存在的键值对数量。

Vue 更新数据 Vue.set 的属性和方法

在对象中新增属性时,页面不会自动更新。可以用 Vue.set 方法解决。 通过下标修改数组中的值,页面也不会自动更新。可以用数组的方法或 Vue.set 方法解决。 特注:Vue.set 不能给 vm 或根数据对象 data 添加属性!!! 修改对象时的问题: <div id="APP"> <h3>{{title}}:</h3> <p>{{info.name}}</p> <p>{{info.age}}</p> <button @click="editAge">修改学生年龄</button> </div> const vm = new Vue({ el: "#APP", data(){ return { title: "学生信息", info:{ name: "张三", age: 20 } } }, methods:{ editAge(){ this.info.age = 26; } } }); 注:当我们修改 data 中原有的数据时,Vue 可以识别到,并且自动更新页面的内容。 但是我们往对象中新增内容时,Vue 就识别不到了。 <div id="APP"> <h3>{{title}}:</h3> <p>姓名:{{info.name}}</p> <p>年龄:{{info.age}}</p> <button @click="addAge">添加学生年龄</button> </div> 注:在页面输出一个对象中没有的属性,并不会发生报错。 const vm = new Vue({ el: "

计算机网络——虚拟机网络的三种模式介绍-桥接模式-NAT模式-仅主机模式

文章目录 一、桥接模式网关 二、NAT模式三、仅主机模式 打开我们的虚拟机,点击编辑—虚拟网络编辑器 就可以查看我们的网络模式 一、桥接模式 桥接模式(Bridge)是指VMware虚拟机软件,模拟了一个虚拟的交换机,将真实机器和虚拟机连接起来,虚拟机可以使用真实机器所在的网段的路由器上网,虚拟机和真实机的地位是平等的。 网关 网关(gateway) 即网络的关口,路由器LAN口的ip地址,是内部PCT的网关,在配置交换机或者PC设备时,如果不填网关,就不能将数据送给路由器。添加默认网关,就是添加默认路由,内网设备要通信,必须要网关。 桥接模式的具体原理如下: 二、NAT模式 NAT模式(network address transfer):实现内网的ip地址和外网的ip进行转换,NAT模式里的真实机器和虚拟机通信是使用vmnet这个接口和虚拟机通信,在交换机上把PC设备的源地址,改成交换机的WAN口地址,目的地址不变,这样才能连到外网。 如果选择NAT模式,内网的虚拟机可以访问外网,但外网的机器不能访问内网,因为外网的机器没有到内网的路由。 三、仅主机模式 仅主机模式(hostonly):默认情况下,虚拟机只能跟真实机通信,不能和其他机器通信(开启电脑的路由功能就可以跟其他的通信) 在我们windows系统看见的网卡分别对应了虚拟机的三种网络模式 vmnet0:桥接模式(会自动捆绑到本地连接上) vmnet1:hostonly模式 vmnet8:NAT模式

VC++6.0配置opencv1.0教程(全网最详细)附加图文

VC++6.0配置opencv1.0教程(全网最详细)附加图文 ((很多评论我没时间看,tiquma写出来了,有兴趣的同学自己找一找8) 配置前 第一次写博客,激动٩(๑>◡<๑)۶,坐标武汉,大三狗,这学期新开了数字图像处理课程,课上老师使用的VC++6.0和opencv1.0,这两个远古软件现在很少有人用了,但是没办法呀,上级实验课都要用,只能慢慢学了。 查了好久发现网上的教程太少了,而且opencv1.0的官网已经不提供下载链接了,搜索的资源都要软妹币,博主自己下载过一次,花了钱不说,文件还不齐全嘤嘤嘤。今天配置好了,打算写一个博客,尝试一下,顺便把这篇文章分享给更多的人,希望能帮到你萌~ ##安装VC++6.0 VC++6.0还是很经典的,网上的下载包也很多,还是习惯用中文版,所以博主就下载了一个中文版。话不多说,需要的自取。VC++6.0中文版 (tiquma: free) ##安装opencv1.0 当初找了好久,我太难了。就冲我的辛苦劲,评论两句小姐姐才可以 Opencv1.0 (tiquma: free) (例子中opencv安装在C:\Program Files)(例子中工程名为LLL,随意) 全局设置:(只用配置一次) • 菜单Tools->Options->Directories:先设置lib路径,选择Library files,在下方填入路径: C:\Program Files\OpenCV\lib • 然后选择include files,在下方填入路径: C:\Program Files\OpenCV\cxcore\include C:\Program Files\OpenCV\cv\include C:\Program Files\OpenCV\otherlibs\highgui C:\Program Files\OpenCV\otherlibs\cvcam\include C:\Program Files\OpenCV\cvaux\include C:\Program Files\OpenCV\ml\include 创建一个MFC工程 • 创建一个MFC工程(MFC AppWizard[exe],单文档) • 在*Doc.h文件中添加OpenCV类文件(如图) #include “cv.h” #include “highgui.h” • 添加成员变量(public:) CvvImage m_img; 项目设置 每创建一个将要使用OpenCV的VC Project,都需要给它指定需要的lib。菜单:Project->Settings,然后将Setting for选为All Configurations,然后选择右边的link标签,在Object/library modules附加上 cxcore.lib cv.lib ml.lib cvaux.lib highgui.lib cvcam.lib 也可以在程序中添加以下代码达到同样的效果: #pragma comment(lib,“cv.lib”) #pragma comment(lib,“cxcore.lib”) #pragma comment(lib,“highgui.

Rabbit mq实现延迟发送消息(死信队列)

注:供个人查阅学习使用,不做其他用途 实现方式: 声明一个TTL交换机,创建队列的时候绑定一个死信交换机,发送消息时往正常队列里放入一条具有超时时间的消息,costomer不对消息进行读取,消息就会进去指定的死信交换机,在costomer绑定死信交换机和死信队列,并进行监听,就可以读取到超时的消息。(也就是自己设置的延迟发送的时间) 准备工作: rabbitmq下载网上有具体的方法,这里暂不详解 pom文件 <!--消息队列中间件--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> <version>2.5.8</version> </dependency> 相关配置文件:根据实际情况进行修改 spring.rabbitmq.host=192.168.31.154 spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=admin123 spring.rabbitmq.virtual-host=/ spring.rabbitmq.template.retry.enabled=true spring.rabbitmq.template.retry.initial-interval=10000ms spring.rabbitmq.template.retry.max-interval=300000ms spring.rabbitmq.template.retry.multiplier=2 spring.rabbitmq.template.exchange=topic.exchange 一、producer创建一个TTL交换机 注:之所以要动态的创建队列,是因为队列遵循先进先出,即使后面的数据过期了也会等前面的数据过期或者被拿走才会进入到死信队列,所以一个TTL队列最好就只遵循一个超时时间 @Configuration public class TTLMqConfig { public static final String QUEUE_EMAIL = "ttl.queue";//队列名称 public static final String EXCHANGE_NAME="ttl.direct";//交换机名称 public static final String ROUTINGKEY_EMAIL="dl"; public static final String DL_EXCHANGE_NAME="dl.ttl.direct";//死信交换机名称 public static final String DL_QUEUE_NAME="dl.ttl.queue";//死信队列名称 /*** * 声明交换机 * @param: [] * @return: org.springframework.amqp.core.DirectExchange * @author: kevin * @date: 2023/3/8 15:20 */ @Bean(EXCHANGE_NAME) public DirectExchange ttlDirectExchange(){ return new DirectExchange(EXCHANGE_NAME); } /*** * 注入rabbitMq admin对象 不然直接引用会空指针 * @param: [connectionFactory] * @return: org.

Python爬虫——Requests库常用方法及参数介绍

Requests 库中定义了七个常用的请求方法,这些方法各自有着不同的作用,在这些请求方法中 requests.get() 与 requests.post() 方法最为常用。请求方法如下所示: 常用请求方法 方法说明requests.request()构造一个请求对象,该方法是实现以下各个方法的基础。requests.get()获取HTML网页的主要方法,对应于 HTTP 的 GET 方法。requests.head()获取HTML网页头信息的方法,对应于 HTTP 的 HEAD 方法。requests.post()获取 HTML 网页提交 POST请求方法,对应于 HTTP 的 POST。requests.put()获取HTML网页提交PUT请求方法,对应于 HTTP 的 PUT。requests.patch()获取HTML网页提交局部修改请求,对应于 HTTP 的 PATCH。requests.delete()获取HTML页面提交删除请求,对应于 HTTP 的 DELETE。 上述方法都提供了相同的参数,其中某些参数已经使用过,比如headers和params,前者用来构造请求头,后者用来构建查询字符串。这些参数对于编写爬虫程序有着至关重要的作用。本节对其他常用参数做重点介绍。 SSL认证-verify参数 SSL 证书是数字证书的一种,类似于驾驶证、护照和营业执照。因为配置在服务器上,也称为 SSL 服务器证书。SSL 证书遵守 SSL 协议,由受信任的数字证书颁发机构 CA(电子认证服务)颁发。 SSL 具有服务器身份验证和数据传输加密功能。 verify参数的作用是检查 SSL 证书认证,参数的默认值为 True,如果设置为 False 则表示不检查 SSL证书,此参数适用于没有经过 CA 机构认证的 HTTPS 类型的网站。其使用格式如下: response = requests.get( url=url, params=params, headers=headers, verify=False ) 代理IP-proxies参数 一些网站为了限制爬虫从而设置了很多反爬策略,其中一项就是针对 IP 地址设置的。比如,访问网站超过规定次数导致流量异常,或者某个时间段内频繁地更换浏览器访问,存在上述行为的 IP 极有可能被网站封杀掉。 代理 IP 就是解决上述问题的,它突破了 IP 地址的访问限制,隐藏了本地网络的真实 IP,而使用第三方 IP 代替自己去访问网站。

《解构领域驱动设计》- 软件复杂度解析

更多内容关注微信公众号:fullstack888 复杂度定义 复杂系统是由大量相互作用的部分组成的系统。与整个系统比起来,这些组成部分相对简单,没有中央控制,组成部分之间也没有全局性的通信,并且组成部分的相互作用导致了复杂行为。 在软件系统中,函数、类、模块、组件和服务等都可以视为组成部分,他们之间的相互作用最终导致了软件系统的复杂行为。 复杂度成因分析 下面通过如下示例来更直观的感受下理解能力和预测能力两个维度对复杂度的描述: 内衣:原理简单,功能单一 手表:结构复杂,功能明确可预测 三人团队:需要通过简单的沟通和协作,做到团队成员间的角色和职责清晰可控 城市:城市建设的空间结构、人员结构都比较复杂,需要人花较多时间才能熟悉,城市的规划也随时间存在不确定性风险,比较难以预测结果 双摆:结构简单,但是对初始设置具有高度敏感性,其行为不可预测 股市:影响因素多且复杂,不可控,不可预测,是个典型的混沌模型 软件系统的复杂度分析 软件系统属于“复杂难解”+“复杂难测”,跟城市建设属于同一复杂度。下面从理解能力和预测能力两方面对软件系统的复杂度进行分析。 理解能力 规模分析 系统规模的扩张,不仅取决于需求的数量,还取决于需求功能点之间的关系,评估软件系统规模的元素包括但不限于以下几个 代码行数 包、类、方法的数量 继承的层次 方法的调用数 圈复杂度 开发过程中有很多的问题会导致软件系统规模的无序扩张,比较典型的有下面几个,资深程序员应该都遇到过 函数存在副作用。调用时可能对函数的结果做了隐含的假设 类的职责繁多,导致开发人员不敢轻易修改,因为不清楚其影响范围 热点代码被频繁变更,职责被包裹了一层又一层,没有清晰的业务边界 隐藏的 bug,在某些个不为人知的诱发条件具备时,就会让整个调用链路崩溃 不同业务场景的不同例外场景,其处理方式各不相同 同步与异步代码混合在一起,不可预知的调用链路顺序 结构分析 结构之所以变得复杂,多数情况下是由系统的质量属性决定的。软件系统从最初的单体系统到现在的分布式微服务体系,整个发展历程一直是不断拆分的微型化过程。软件系统的复杂同时也会加剧人员组织结构的复杂度。康威定律指出,任何组织在设计一套系统(广义概念上的系统)时,所交付的设计方案在结构上都与该组织的沟通结构保持一致。 无论是优雅的设计还是拙劣的设计都会给系统带来复杂度的增加,不同的是,优雅的设计是主动控制结构的复杂度,拙劣的设计带来的复杂度是偶发的,无序的,是技术债。 无序设计的几个典型表现: 代码没有显而易见的进入系统的入口 不存在一致性,不存在风格,也没有将不同的部分组织在一起的统一概念 系统中的控制流让人觉得不舒服,无法预测 系统中有太多“坏味道” 数据很少放在他被使用的地方,滥用缓存,视图让数据停留在更方便的地方 预测能力 影响预测能力的关键要素在于变化,而我们无法预知未来,也就无法预测未来可能发生的变化,这就带来了软件系统的不可预测性。对变化的应对不妥,就会导致软件系统的过度设计或设计不足。 过度设计的表现 引入不必要的抽象来保证产品的可扩展性 设计不足的表现 没有明确识别出未来确认会发生的变化,或者对需求变化发展的方向缺乏前瞻 如何控制软件复杂度 控制规模 领域驱动设计对软件复杂度的控制之道就是竭力改变设计的质量,然后在解空间中通过“分而治之”的方法将庞大的系统拆分为一个个小的软件元素来解决问题空间中的一个个细粒度的问题。拆分手段就是限界上下文和上下文映射,它们是战略设计阶段的核心。 清晰结构 为避免业务逻辑的复杂度与技术实现的复杂度混杂在一起,就需要确定业务逻辑与技术实现的边界,从而隔离各自的复杂度。这种隔离也符合关注点分离的设计原则。为此,领域驱动设计引入了分层架构,分层架构将业务逻辑封装到领域层,支撑业务逻辑的技术实现放到基础设施层,应用层既扮演了领域层的外观,又解决了业务逻辑跟技术实现的协作问题。 领域驱动设计通过限界上下文隔离了业务能力的边界,通过分层架构隔离了业务逻辑与技术实现,如此,保证了整个系统具有了清晰的结构,实现了有序设计。 响应变化 应对变化最好的方式就是将变化锁进笼子里,通过模式等抽象方法将不同维度、不同粒度的变化限定在一个可控的范围内,当变化来临时能及时感知,并作出最小的适应性改动。 通过领域建模可以将看似分散的事务抽象成一个统一的领域模型,将复杂的业务通过可视化的方式表达出来。当需求发生变化时,通过比对抽象出来的业务模型,即可敏锐的发现增量变化的部分,从而以最小的代价响应新增的需求。 - END - 往期回顾 ◆从传统数据库痛点看分布式数据库选型问题 ◆日志的艺术 ◆更人性化的无阈值监控不再为无效告警烦恼 ◆SQL查找是否"存在",别再count了! ◆最大连接数65535,服务器是如何应对百万千万的并发的? ◆5 分钟搞懂 Web3 架构 ◆一支不足百人的团队创造了 ChatGPT :90 后挑大梁,应届生 11 人,华人抢眼

视觉学习笔记10——opencv的卸载、安装与多版本管理

系列文章目录 参考文献 参考文献 参考文献 参考文献 文章目录 系列文章目录前言一、opencv卸载二、opencv安装1、下载opencv2、cmake-gui编译3、终端编译安装4、配置环境变量报错一报错二报错三报错四 5、opencv的多版本安装与管理多版本安装环境变量管理 前言 之前在ubuntu18系统上已经安装了opencv4.4.0和扩展库opencv_contrib,但是最近需要跑一个SLAM的源代码,而这个SLAM系统是基于opencv3.4.2开发的,直接运行会出现很多opencv版本不兼容的问题。因此想再安装opencv3.4.2和扩展库opencv_contrib3.4.2,过程中出现了很多问题,写这篇文章记录一下。 一、opencv卸载 卸载原有Opencv 在ubuntu终端命令行输入以下命令进入安装opencv的build目录并进行卸载操作。 cd build sudo make uninstall cd .. sudo rm -r build 最后在输入以下命令清理/usr中所有opencv相关项即可。(此步骤可不需要) sudo rm -r /usr/local/include/opencv2 /usr/local/include/opencv /usr/include/opencv /usr/include/opencv2 /usr/local/share/opencv /usr/local/share/OpenCV /usr/share/opencv /usr/share/OpenCV /usr/local/bin/opencv* /usr/local/lib/libopencv* 二、opencv安装 1、下载opencv 以opencv3.4.2为例,进入官网和github分别下载Opencv3.4.2 Sources和openc_contrib,注意两者的版本一定是对应的,最后将contrib压缩包解压后放进之前解压好的Opencv Sources的文件夹下。 在这里提前打个补丁,因为在后面编译OpenCV 以及 openc_contrib 时很容易出现提示:缺少boostdesc_bgm.i文件出错。可能是因为墙的问题,有一些文件下载不全 总共缺了以下几个文件: boostdesc_bgm.i boostdesc_bgm_bi.i boostdesc_bgm_hd.i boostdesc_lbgm.i boostdesc_binboost_064.i boostdesc_binboost_128.i boostdesc_binboost_256.i vgg_generated_120.i vgg_generated_64.i vgg_generated_80.i vgg_generated_48.i 所以需要手动打补丁。 这里感谢这位博主贡献的资源,自行下载。 https://blog.csdn.net/AlexWang30/article/details/99612188 下载的补丁解压到对应的opencv-3.4.2/opencv_contrib-3.4.2/modules/xfeatures2d/boostdesc_vgg_11/目录下,并更改opencv-3.4.2/opencv_contrib-3.4.2/modules/xfeatures2d/cmake下的两个文件,修改它的下载路径,指向本地。 2、cmake-gui编译 官网下载cmake(我用的是3.14,直接终端下载的话版本很低,且听说会有点问题),解压后打开cmake-gui。 在opencv3.4.2中创建一个build文件夹,打开自己的cmake-gui,选择打开对应路径,然后点击configure按键。 注意,这个安装位置就很重要,如果你是有多opencv的需求那么一定要修改默认位置,不然会有大问题,如果你只用一个那么你可以修改也可以不用修改。因为我接下来是需要实现多opencv的,所以我这里就进行了修改。 修改CMAKE_INSTALL_PREFIX的默认安装目录为/usr/local/opencv/opencv3.4.2 在OPENCV_EXTRA_MODULES_PATH处,选择opencv_contrib3.4.5扩展库的输入目录(单击这一行后方空白处即可选中)然后选择opencv_contrib-3.2.0文件夹中的modules文件夹,注意,不是只选中opencv_contrib-3.2.0文件夹就好了,需要选中里面的modules文件夹!

C语言程序设计经典例题100道(二)

编写C语言程序,从键盘上输入两个整数,如果这两个数的数值相等,则输出“相等”的信息到屏幕中;否则输出“不相等”的信息到屏幕上。 #include<stdio.h> int main() { int x,y; printf("请输入x:"); scanf("%d",&x); printf("请输入y:"); scanf("%d",&y); if(x==y) { printf("x与y相等"); } else { printf("x与y不相等"); } return 0; } 运行结果 编写C语言程序,从键盘输入3个整数并输出这三个整数中的最小值到屏幕中。 #include<stdio.h> int main() { int a,b,c; int min; printf("请输入整数a:"); scanf("%d",&a); printf("请输入整数b:"); scanf("%d",&b); printf("请输入整数c:"); scanf("%d",&c); if(a<b) { min=a; } else { min=b; } if(c<min) { min=c; } printf("最小值是:%d",min); return 0; } 运行结果 编写C语言程序,从键盘输入一个整数,如果该整数在1~7范围内,则相应输出“星期一”至“星期天“到屏幕中;如果该整数不是1~7,则输出”非法数据“。 #include<stdio.h> int main() { int day; printf("请输入一个数:"); scanf("%d",&day); if(day==1) { printf("星期一\n"); } else if(day==2) { printf("

Python+Opencv实现无参数、全自动的Canny算法

目录 一、什么是Canny边缘检测算法?二、最优边缘准则是什么?三、Canny算法实现步骤四、Canny算法在使用中的问题?五、无参数、自动化Canny算法代码实现六、改进算法效果展示七、问题探讨参考资料注意事项 一、什么是Canny边缘检测算法? Canny边缘检测算子是John F. Canny于 1986 年开发出来的一个多级边缘检测算法。更为重要的是 Canny 创立了边缘检测计算理论(Computational theory of edge detection)解释这项技术如何工作。 通常情况下边缘检测的目的是在保留原有图像属性的情况下,显著减少图像的数据规模。目前有多种算法可以进行边缘检测,虽然Canny算法年代久远,但可以说它是边缘检测的一种标准算法,而且仍在研究中广泛使用。其效果如下图所示: 二、最优边缘准则是什么? 最优检测:算法能够尽可能多地标识出图像中的实际边缘,漏检真实边缘的概率和误检非边缘的概率都尽可能小;最优定位准则:检测到的边缘点的位置距离实际边缘点的位置最近,或者是由于噪声影响引起检测出的边缘偏离物体的真实边缘的程度最小;检测点与边缘点一一对应:算子检测的边缘点与实际边缘点应该是一一对应。为了满足这些要求 Canny 使用了变分法(calculus of variations),这是一种寻找优化特定功能的函数的方法。最优检测使用四个指数函数项表示,但是它非常近似于高斯函数的一阶导数 三、Canny算法实现步骤 应用高斯滤波来平滑图像,目的是去除噪声;计算图像的强度梯度(intensity gradients);应用非最大抑制(non-maximum suppression)技术来消除边误检(本来不是但检测出来是);应用双阈值的方法来决定可能的(潜在的)边界;利用滞后技术来跟踪边界。 具体的实现细节可以查看该链接。 四、Canny算法在使用中的问题? Canny算法的检测效果很好,得到了广泛的应用。它经常出现在一些算法的预处理阶段,除此之外,很多计算机视觉库中都集成了Canny算,代表性的包括Opencv,cv2.canny(image, lower, upper)是Opencv中的Canny算法的调用接口。**但是大家在调用的过程中都会遇到一个难题-lower和upper参数如何来设置呢?**很多人采取的方法是减少范围不断的去尝试直到找到一个合适的阈值,但是这种方法费时费力,而且鲁棒性较差。**你经常会发现,这个参数适用于这张图片但是当你输入另外一张图片时效果就不好啦!**本文的主要目的就是来解决这个问题的! 五、无参数、自动化Canny算法代码实现 # -*- coding: utf-8 -*- # 导入一些python包 import numpy as np import argparse import glob import cv2 import os # 定义auto_canny函数 def auto_canny(image, sigma=0.33): # 计算单通道像素强度的中位数 v = np.median(image) # 选择合适的lower和upper值,然后应用它们 lower = int(max(0, (1.0 - sigma) * v)) upper = int(min(255, (1.

Windows查询计算机设备序列号、MAC地址和硬盘序列号

1 进入命令提示符 搜索cmd,以管理员身份打开命令提示符 2 查询设备序列号 输入命令 wmic bios get serialnumber 返回的字符串即为设备序列号(SerialNumber) 3 查询MAC地址 输入命令 ipconfig /all 返回物理地址即为所需MAC地址 需要注意的是:通常会出现若干个“物理地址”,那些显示”媒体已断开连接“的就不需要关心啦! 4 查询硬盘序列号 输入以下命令 wmic diskdrive get serialnumber 返回的字符串即为硬盘序列号。通常有几个硬盘就会有几个序列号。

Python123.io---输出N以内的所有素数

输出N以内的所有素数 类型:函数‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬ 描述‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬ 编程找出N(即小于等于N)的所有素数。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬ 输入格式‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬ 输入一个正整数‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬ 输出格式‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬ 在同一行中从小到大依次输出不大于n的全部素数,每个数字后面一个空格。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬ 示例 1‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬ 输入:97 输出:2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 代码实现: def is_prime(n): """判断素数的函数,接收一个正整数为参数,参数是素数时返回True,否则返回False。减小判定区间,减少循环次数,提升效率""" #======================================================= # 补充你的代码 i = 2 while n % i != 0 and i <= n**0.5: i += 1 if i > n**0.5: return True else: return False #=======================================================

模型转换、模型压缩、模型加速工具汇总

目录 一、场景需求解读二、模型转化工具汇总1、模型转换工具的作用2、模型转换工具简介1、MMdnn2、 ONNX3、 X2Paddle 三、模型压缩和加速工具汇总1、模型压缩加速工具的作用2、模型压缩加速工具简介1、PocketFlow3、distiller4、TVM5、tflite6、ncnn7、MNN8、OpenVIO9、Tengine10、ARMNN11、Paddle Lite12、FeatherCNN13、DNNL14、MACE15、SNPE16、model-compression17、MediaPipe18、Glow19、TNN20、Tengine Lite21、rknn与rknpu 四、其它加速工具1、Halide2、TACO3、weld4、ATLAS5、TensorComprehensions6、opentuner 参考资料注意事项 一、场景需求解读 在现实场景中,我们经常会遇到这样一个问题,即某篇论文的结果很棒,但是作者提供的训练模型是使用pytorch训练的,而我自己却比较擅长用tensorflow,我想要使用该模型做一些其它的项目。那么很多人就会采取一种方式,去阅读别人的论文、理解别人的代码,然后使用自己熟悉的工具进行代码重现、重新训练一个模型。这个阶段会耗用大量的人力和物力,最终还不能保证一定能得到论文的效果。本文即将介绍的几个模型转换的工具就可以很好的帮你解决你的这个问题,比较有名的包括mmdnn、onnx等。 除此之外,我们的目的是将深度学习模型应用到现实场景中的任务中,但是现实场景中的硬件五花八门,包含着大多数的算力不足的设备,以ARM处理处居多。那么这里面就涉及到了一个问题,即使你说你的模型有多牛逼,但是如果你的模型比较大,需要大量的算力才能跑起来,那么对于应用场景而言,你这个算法其实没有多少利用价值的。为了将使用N卡的GPU训练出来的模型成功的部署在这些低功耗的设备上面,我们通常需要对这些模型进行模型压缩和模型加速操作,比较有名的几个工具包括TensorRT、PocketFlow、TVM等。 二、模型转化工具汇总 1、模型转换工具的作用 简而言之,模型转换工具的作用是:将使用不同训练框架训练出来的模型相互联系起来,用户可以进行快速的转换,节省了大量的人力和物力花销。 2、模型转换工具简介 1、MMdnn 官网链接 上图展示了MMdnn的主要功能。MMDNN是一套帮助用户在不同的深度学习框架之间进行交互操作的工具。例如,模型转换和可视化。转换caffe、keras、mxnet、tensorflow、cntk、pytorch onnx和coreml之间的模型。 简而言之,通过这个工具,我们可以方便的将某一个框架训练出来的模型转换成另外一个框架所支持的模型,图中基本上包含了当前所有主流的深度学习训练框架,包括Tensorflow、Pytorch、Caffe、MxNet等。除此之外,图中包含了一个关键的概念,那就是Intermediate Representation-中间表示,即这个工具首先将输入框架的模型转换为IR,然后通过IR转换成另外一个框架所支持的模型。 上图展示了MMdnn工具当前所支持的模型。上面的对号表示的是你可以随意的在不同框架之间进行该模型的转换。 # 将Tensorflow的resnet_v2_152模型转换为Pytorch支持的模型 mmdownload -f tensorflow -n resnet_v2_152 -o ./ mmconvert -sf tensorflow -in imagenet_resnet_v2_152.ckpt.meta -iw imagenet_resnet_v2_152.ckpt --dstNodeName MMdnn_Output -df pytorch -om tf_resnet_to_pth.pth 上面展示了一个简单的使用案例,通过简单的两行指令就可以将Tensorlfow的模型转换为pytorch所支持的模型,是不是很方便呢! 2、 ONNX 官网链接 ONNX是一个开放的生态系统,它使人工智能开发者能够随着项目的发展选择正确的工具。ONNX为人工智能模型提供了一种开源格式,包括深度学习和传统的ML。它定义了一个可扩展的计算图模型,以及内置运算符和标准数据类型的定义。目前,我们关注的是推断(评分)所需的能力。 ONNX得到了广泛的支持,它可以应用到很多框架、工具和硬件中。它可以实现不同框架之间的相互转换,并加速研究到产品的速度。 上图展示了ONNX所支持的一些深度学习框架,图中包括了一些主流的框架,但是并不完善,tensorflow的身影竟然没有出现。 上图展示了该工具所支持的一些Converters,不仅包括深度学习框架Tensorflow、Keras等,而且包括ML工具Scikit-learn、Xgboost、LibSVM等。 上图展示了该工具所支持的一些Runtimes(运行时),它更偏向模型的部署端,图中包含了多个大厂,包括NVIDIA、Qualcomm、Tencent、synppsys等。 上图展示了该工具所支持的底层编译器,包括了大名鼎鼎的TVM,下面会对该工具进行详细的介绍。除此之外,包含了一些可视化网络模型的工具,NETRON工具相当好用,具体的细节请看这里。 3、 X2Paddle 官网链接 X2Paddle支持将其余深度学习框架训练得到的模型,转换至PaddlePaddle模型。一个比较小众的工具,感兴趣的请在官网查看具体的细节,这里不再祥述。 三、模型压缩和加速工具汇总 1、模型压缩加速工具的作用 简而言之,模型压缩加速工具的作用是:将训练好的模型进行压缩和加速,然后将其部署到一些特定的设备上去,从而满足现实场景的需求。 2、模型压缩加速工具简介 1、PocketFlow 官网链接 PocketFlow是一个开源框架,可以使用最少的人力压缩和加速深度学习模型。深度学习广泛应用于计算机视觉、语音识别、自然语言翻译等各个领域。然而,深度学习模型通常计算成本很高,这限制了在计算资源有限的移动设备上的进一步应用。 PocketFlow旨在为开发人员提供一个易于使用的工具包,以提高推理效率,而不会降低或降低性能。开发人员只需要指定所需的压缩比或加速比,然后PocketFlow将自动选择适当的超参数来生成高效的压缩模型以进行部署。 上图展示了PocketFlow的整个框架。该框架主要由两类算法组件组成,即学习器和超参数优化器,如上图所示。给定一个未压缩的原始模型,学习模块使用随机选择的超参数组合生成一个候选压缩模型。然后对候选模型的精度和计算效率进行评估,并将其作为反馈信号,用于确定学习模块要探索的下一个超参数组合。经过几次迭代,所有候选模型中最好的一个输出为最终的压缩模型。 上图展示了该工具中所包含的压缩方法。主要包括3大类:裁剪、权重稀疏和量化。

软件测试常见面试题合集(内附详细答案)

最近看到网上流传着各种面试经验及面试题,往往都是一大堆技术题目贴上去,但是没有答案。 为此我业余时间整理了这份软件测试基础常见的面试题及详细答案,望各路大牛发现不对的地方不吝赐教,留言即可。 01 软件测试理论部分 1.1 测试概念 1. 请你分别介绍一下单元测试、集成测试、系统测试、验收测试、回归测试 单元测试:完成最小的软件设计单元(模块)的验证工作,目标是确保模块被正确的编码 集成测试:通过测试发现与模块接口有关的问题 系统测试:是基于系统整体需求说明书的黑盒类测试,应覆盖系统所有联合的部件 回归测试:回归测试是指在发生修改之后重新测试先前的测试用例以保证修改的正确性 验收测试:这时相关的用户或独立测试人员根据测试计划和结果对系统进行测试和接收。验收测试包括Alpha测试和Beta测试。 Alpha测试:是由用户在开发者的场所来进行的,在一个受控的环境中进行。并且在开发者对用户的指导下进行测试,开发者负责记录发现的错误和使用中遇到的问题 Beta测试 :由软件的最终用户在一个或多个用户场所来进行的,开发者通常不在现场。由用户记录在测试中遇到的一系列问题,并定期报给开发者。 2. 什么是黑盒?什么是白盒?黑盒和白盒的测试方法分别有哪些? 黑盒:黑盒测试也称功能测试或数据驱动测试。把程序看作一个不能打开的黑盆子,在完全不考虑程序内部结构和内部特性的情况下,对程序接口进行测试。“黑盒”法着眼于程序外部结构、不考虑内部逻辑结构、针对软件界面和软件功能进行测试 常用的黑盒测试方法:等价类划分法;边界值分析法;因果图法;场景法;正交实验设计法;判定表驱动分析法;错误推测法;功能图分析法。 白盒测试:也称为结构测试或逻辑驱动测试,是针对被测单元内部是如何进行工作的测试 常用白盒测试方法 静态测试:不用运行程序的测试; 动态测试:需要执行代码,通过运行程序找到问题; 逻辑覆盖包括:语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖和路径覆盖 1.语句覆盖每条语句至少执行一次。 2.判定覆盖每个判定的每个分支至少执行一次。 3.条件覆盖每个判定的每个条件应取到各种可能的值。 4.判定/条件覆盖同时满足判定覆盖条件覆盖。 5.条件组合覆盖每个判定中各条件的每一种组合至少出现一次。 6.路径覆盖使程序中每一条可能的路径至少执行一次。 3. 测试流程: 需求测试->概要设计测试->详细设计测试->单元测试->集成测试->系统测试->验收测试 4. app测试性能指标 内存 cpu 流量 启动速度 5. web测试和app测试不同点 系统架构方面: web项目,一般都是b/s架构,基于浏览器的 app项目,则是c/s的,必须要有客户端,用户需要安装客户端。 web测试只要更新了服务器端,客户端就会同步会更新。App项目 则需要客户端和服务器都更新。 性能方面: web页面主要会关注响应时间 而app则还需要关心流量、电量、CPU、GPU、Memory等。 兼容方面: web是基于浏览器的,所以更倾向于浏览器和电脑硬件,电脑系统方面的兼容 app测试则要看分辨率,屏幕尺寸,操作系统、网络。 web测试是基于浏览器的所以不必考虑安装卸载。 而app是客户端的,则必须测试安装、更新、卸载。除了常规的安装、更新、卸载还要考虑到异常场景:包括安装时的中断、弱网、安装后删除安装文件 。 6. 缺陷按优先级分为哪些类型? p1-p5 面试重点 缺陷必须立即解决 缺陷要求正常排队等待修复 缺陷可以在方便时被纠正 下一个版本修复 不修复 7. 测试用例的内容是什么? 面试重点 用例编号

用百度地图API和echarts时遇到的一些问题

Uncaught TypeError: Cannot read properties of undefined (reading 'extendComponentModel') 原因:这个错误通常是引入了不兼容版本的echarts库导致的 确保echarts库的版本与使用的API版本兼容,建议使用echarts提供的在线本版 <scriptsrc="" target="_blank">https://cdn.jsdelivr.net/npm/echarts@latest/dist/echarts.min.js"></script> Uncaught TypeError: Cannot read properties of undefined (reading 'extendComponentModel') at VM11821 bmap.min.js:22:2905 原因:这个错误通常是因为引入的百度地图 API 版本与 echarts 百度地图扩展版本不兼容所致 确保 echarts 百度地图扩展版本与使用的百度地图 API 版本兼容 建议直接使用echarts官方提供的CDN: <scriptsrc="" target="_blank">https://cdn.jsdelivr.net/npm/echarts@latest/dist/echarts.min.js"></script> 总结 遇到以上两个错误的,可以直接复制下面三行: 通过<script>标签引入地图api地址、echarts地址、扩展插件地址,这里的ak是你在地图服务中心注册的 <!-- 百度 --> <script src="https://api.map.baidu.com/api?v=3.0&ak=?"></script> <!-- echarts --> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script> <!-- 扩展地图插件 --> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/echarts@5/dist/extension/bmap.min.js"></script>

单链表的构造及其功能

定义 线性表的链式存储又称单链表,它是指通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表节点,除存放元素自身的信息外,还需要存放一个指向其后继的指针。 单链表的优缺点 优点 : 1、增加、删除元素方便,不用大量移动元素 2、不需要空间提前开辟,易扩充 缺点 : 1、不支持随机存储 2、开辟了指针域,会浪费额外的空间 单链表的初始化 LinkList InitList(){ //初始化 LinkList L = (LinkList)malloc(sizeof(LNode)); //C开辟动态内存 //L = new (LNode); //C++开辟动态内存 if (L == NULL){ return NULL; //内存不足,分配失败 } L->next = NULL; //将L的指针域设为空 return L; } 单链表的头插法的构建 优点:可用于链表的逆置 LinkList List_Front_Insert(LinkList L){ //初始化头插 printf("请输入数据(-1结束):"); //连续输入数据,-1结束 int n; LNode* newNode; //新节点 scanf("%d", &n); while (n != -1){ newNode = (LNode*)malloc(sizeof(LNode)); //为新节点开辟空间 newNode->data = n; newNode->next = L->next; L->next = newNode; scanf("

使用python实现矩阵

文章目录 矩阵__init____getitem____setitem__reshape__repr____add__ 与 __mul____matmul__LU分解转置利用LU分解求行列式 利用LU分解解线性方程组 矩阵 使用python构建一个类,模拟矩阵,可以进行各种矩阵的计算,与各种方便的用法 init from array import array class Matrix: def __init__(self, matrix: 'a list of one dimension', shape: 'a tuple of shape' = None, dtype: 'data type code' = 'd'): # matrix一个包含所有元素的列表,shape指定形状,默认为列向量,dtype是数据类型 # 使用一个数组模拟矩阵,通过操作这个数组完成矩阵的运算 self.shape = (len(matrix), 1) if shape: self.shape = shape self.array = array(dtype, matrix) getitem 由于矩阵是一个二维数组,应当支持诸如matrix[1, 2],matrix[1:3, 2],matrix[1:3, 2:4]之类的取值 所以我们需要使用slice类的indice方法实现__getitem__,并支持切片 def __getitem__(self, item: 'a index of two dimensions'): # 使用slice类的indices方法,实现二维切片 rows, cols = item # 下面对传入的指针或者切片进行处理,使其可以统一处理 if isinstance(rows, slice): rows = rows.

谷歌浏览器F12控制台的秘密

作为一名程序员无论是前端还是后端调试的时候都离不开控制台,那么我今天就来分享几个小技巧 一.network栏 这是访问csdn开启控制台的效果 1.1复制请求再浏览器里发送请求 当你和别人联调的时候,他可能想看看你的接口,但是他没有token,也没有postman只有个浏览器怎么办呢,我们再请求上右键; 这个copy了以后我们直接在浏览器f12的console发起请求就行了,也会在network中记录的 2.2 想重新发送一个请求却不想刷新浏览器 我们有时候想看日志让页面重新发起请求,但刷新页面 有可能发送好几个请求,那么日志就很乱,我只想重新发送某一个请求怎么办,又不想刷新页面 这个就可以了,快去试试吧,请求也会在network里记录的 2023年补充,新版本的google已经去掉了Replay XHR这个选项,但是还是有发单个请求的方法的,具体方法就如1.1里的fetch 复制之后去consle里面粘贴然后enter就可以了,network也可以看到这个请求哦 2.3用postman导入一个请求 复制这个,打开postman,复制到这里就可以了 好了去玩吧!

C++中的双冒号::

在C++中,双冒号(::)被用作作用域解析运算符。 类作用域解析运算符 在C++中,如果要在类的定义外部定义或实现成员函数或静态成员变量,则必须使用双冒号运算符来引用类作用域中的成员。例如,如果有一个类叫做MyClass,其中有一个名为myMethod的成员函数,则可以使用以下方式引用该函数: void MyClass::myMethod() { //函数体 } 其中的MyClass::表示myMethod属于MyClass类的作用域。 命名空间作用域解析运算符 在C++中,可以使用命名空间来避免名称冲突。如果在不同的命名空间中有同名的函数或变量,则需要使用双冒号运算符来指定使用哪个命名空间中的函数或变量。例如: namespace ns1 { int x = 1; void foo() { std::cout << "ns1::foo() called" << std::endl; } } namespace ns2 { int x = 2; void foo() { std::cout << "ns2::foo() called" << std::endl; } } int main() { std::cout << ns1::x << std::endl; // 输出 1 std::cout << ns2::x << std::endl; // 输出 2 ns1::foo(); // 输出 "

实现幂等性的3种方案

一、什么是幂等性 幂等是一个数学与计算机概念,在数学中某一元预算为幂等时,其作用在任一元素两次后会和其作用一次的结果相同。 在计算机中,一个幂等操作的特点是其任意执行多次执行产生的影响均与执行一次产生的影响相同。幂等函数或者幂等方法是指可以使用相同的参数重复执行,并能获得相同结果的函数和方法。 二、接口幂等性 在HTTP/1.1中,对幂等性进行了定义。它描述了一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外),即第一次请求的时候对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用。 三、为什么需要实现幂等性 1.防止客户端表单重提交:客户填写表单信息提交后,可能由于网络延迟等原因,未及时给客户提出成功响应,导致客户认为没有提交成功,然后一直点提交按钮,这时就会产生重复提交表单请求。 2.用户恶意刷单:如投票,明确一人一天只能投1票,若不做幂等校验,可能会收到客户重复提交的投票信息。 3.接口超时重试:现在大多数后台都是基于springcloud搭建的微服务建构,服务端与服务端之间的调用,可能有超时,失败等重试机制,也有可能存在多次请求,造成数据重复问题。 4.mq重复消费:在消费mq时,可能发生重复消费等问题。 四、引入幂等性校验后会产生什么影响 1.增加服务端业务处理的复杂性 五、如何实现幂等性 1.数据库唯一性主键 利用数据库唯一性索引保证数据插入或者删除时的幂等性 适用场景: 新增数据、删除数据 流程: 流程细节: (1)外部在页面发起填写表单的请求 (2) 客户端发起获取分布式唯一id请求,分布式唯一Id可以是“雪花算法”,“美团leaf区域Id”,redis自增id。 (3)客户端填写表单数据发起请求时,带上分布式唯一性id (4)后台新增数据时,数据库做主键id唯一性校验。 2.利用乐观锁 在数据表字段新增version字段,修改数据时带上version条件。 适用场景:更新操作 3.防重token令牌 方法描述: 客户端发起请求前,先调用服务端获取token令牌接口,服务端将token令牌作为key存于redis,客户端发起真正发起请求时带上token令牌,服务端拿到token令牌去redis做删除,若能删除成功表示是第一次提交,若删除失败(已被删除)则表示不是第一次提交。 适用场景:新增数据、修改数据、删除数据 流程描述

vue项目发布有缓存,正式环境不更新(解决方案)

前言:每次测试构建或者打包更新版本发到服务器上,导致偶尔会出现不能及时更新到最新代码,浏览器存在缓存的问题。 一、js、css文件防缓存 定义版本变量: const Version = new Date().getTime(); // 这里使用的是时间戳 来区分 ,实际上不用加时间戳,webpack内部还自动变化hash值 output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].[chunkhash].'+_Version+'js'), chunkFilename: utils.assetsPath('js/[id].[chunkhash].'+_Version+'js') } 二、html文件防缓存 方法1、Linux服务器设置nginx禁用html缓存 在开发调试web的时候,经常会碰到因浏览器缓存(cache)而经常要去清空缓存或者强制刷新来测试的烦恼,提供下apache不缓存配置和nginx不缓存配置的设置。在常用的缓存设置里面有两种方式,都是使用add_header来设置:分别为Cache-Control和Pragma。 add_header Cache-Control no-store; add_header Pragma no-cache; server { listen 80; server_name test.exmaple.cn; location / { if ($request_filename ~* .*\.(?:htm|html)$) ## 配置页面不缓存html和htm结尾的文件 { add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; } root /web/; index index.html; try_files $uri $uri/ /index.html =404; } } 方法2、index.html页面添加 <meta http-equiv="Expires" content="0"> <meta http-equiv="

Oracle oci.dll下载地址

下载方式:百度网盘(本人微信:Virgo_zhixin,链接到期了的话私聊或评论) Desc:最近本人这边入职了一家新的公司,由于之前个人使用MySQL更多,所以环境资源筹备不齐全,现在这边新公司所用的数据库是Oracle,我又只待见navicat,没办法,只能配置oci文件来连接了。于是发现Oracle官网下载包含这个文件的压缩包发现下载速度奇慢无比,毕竟是外网资源,所以在千疮百孔的找到之后决定分享一下该资源文件,为遇到相同困难的码农出一份力。 此链接内包含两个版本的oci(11_2/21_3) 链接:https://pan.baidu.com/s/1XlkWR-GFxgKe1R09wXq9Ww 提取码:o70r 下方navicat配置oci教程 如果正巧你也用的navicat而且不会配置的话那么可以看看下文了。 ①下载完以后复制粘贴到navicat的目录内并解压缩(这个时候保证你的navicat没有在运行) ②打开navicat依次点击 工具-选项-环境 ③在上图下面的oci环境下面可以看到目前对应的oci文件位置,点击右边的三个点选择新解压出来的oci ④选择完毕以后点击确定,然后重启navicat即可

数据挖掘实验:关联规则分析之Apriori算法的实现

一、实验原理 Apriori算法是第一个关联规则挖掘算法,也是最经典的算法。它利用逐层搜索的迭代方法找出数据库中项集的关系,以形成规则,其过程由连接(类矩阵运算)与剪枝(去掉那些没必要的中间结果)组成。该算法中项集的概念即为项的集合。包含K个项的集合为k项集。项集出现的频率是包含项集的事务数,称为项集的频率。如果某项集满足最小支持度,则称它为频繁项集。 二、实验内容 三、实验过程 python实现Apriori算法 from __future__ import print_function import pandas as pd #自定义连接函数,用于实现L_{k-1}到C_k的连接 def connect_string(x, ms): x = list(map(lambda i:sorted(i.split(ms)), x)) l = len(x[0]) r = [] for i in range(len(x)): for j in range(i,len(x)): if x[i][:l-1] == x[j][:l-1] and x[i][l-1] != x[j][l-1]: r.append(x[i][:l-1]+sorted([x[j][l-1],x[i][l-1]])) return r #寻找关联规则的函数 def find_rule(d, support, confidence, ms = u'--'): result = pd.DataFrame(index=['support', 'confidence']) #定义输出结果 support_series = 1.0*d.sum()/len(d) #支持度序列 column = list(support_series[support_series > support].index) #初步根据支持度筛选 k = 0 while len(column) > 1: k = k+1 print(u'\n正在进行第%s次搜索.

在Express中使用JWT的操作与报错问题

安装JWT相关的包 运行如下命令,安装如下两个JWT相关的包: npm install jsonwebtoken express-jwt 其中: jsonwebtoken 用于生成JWT字符串express-jwt 用于将JWT字符串解析还原成JSON对象 导入JWT相关的包 使用 require() 函数,分别导入JWT相关的两个包: //导入用于生成JWT字符串的包 const jwt = require('jsonwebtoken'); //导入用于将客户端发送过来的JWT字符串解析还原成JSON对象的包 const expressJWT = require('express-jwt'); 定义secret密钥 为了保证JWT字符串的安全性,防止JWT字符串在网络传输过程中被人破解,需要定义一个用于加密和解密的secret密钥: 当生成JWT字符串的时候,需要使用secret密钥对用户的信息进行加密,最终得到加密好的JWT字符串当把JWT字符串解析还原成JSON对象的时候,需要使用secret密钥进行解密 //secret 密钥的本质: 一个字符串 const secretKey = 'secretkey!!!' 在登录成功后生成JWT字符串 调用jsonwebtoken包提供的 sign() 方法,将用户的信息加密成JWT字符串,响应给客户端: app.post('/api/login', (req, res) => { //将 req.body 请求体中的数据 转存为 userinfo 常量 const userinfo = req.body; //登录失败 if (userinfo.username !== 'admin' || userinfo.password !== '000000') { return res.send({ status: 400, msg: '登录失败!' }) } //登录成功 //在登录成功之后 调用 jwt.

将Conda Prompt Here添加到右键菜单

如何将Conda Prompt Here添加到右键菜单 Conda是一个非常流行的Python的环境管理工具,在做项目的时候把它跟IDE整合在一起用来管理不同项目的环境会很方便,但是在日常使用Windows的过程中如果想用Python写点代码来完成重复性工作,就要在命令行里把Conda从默认目录一路切换到当前文件夹,让人觉得很麻烦。下面就介绍两种方法在右键菜单中添加“Conda Prompt Here”来在当前目录打开Conda,省去切换目录的繁琐操作。 方法1:使用命令行 安装Anaconda或Miniconda,并记录安装位置。这里以 C:\miniconda3 为例,若安装在其他目录,可以自行替换路径。 以管理员权限打开cmd.exe,如果要把Conda Prompt Here添加到空白处的右键菜单,输入以下命令: REG ADD HKCR\Directory\Background\shell\Conda\ /ve /f /d "Conda Prompt Here" REG ADD HKCR\Directory\Background\shell\Conda\ /v Icon /f /t REG_EXPAND_SZ /d C:\miniconda3\Menu\Iconleak-Atrous-Console.ico REG ADD HKCR\Directory\Background\shell\Conda\command /f /ve /t REG_EXPAND_SZ /d "%windir%\System32\cmd.exe "/K" C:\miniconda3\Scripts\activate.bat 如果要把Conda Prompt Here添加到目录的右键菜单,输入以下命令: REG ADD HKCR\Directory\shell\Conda\ /ve /f /d "Conda Prompt Here" REG ADD HKCR\Directory\shell\Conda\ /v Icon /f /t REG_EXPAND_SZ /d C:\miniconda3\Menu\Iconleak-Atrous-Console.ico REG ADD HKCR\Directory\shell\Conda\command /f /ve /t REG_EXPAND_SZ /d "

共享内存shmget传输数据

共享内存的接口函数以及指令 1.查看系统中的共享存储段 ipcs -m 删除系统中的共享存储段 ipcrm -m [shmid] 3.shmget ( ):创建共享内存 int shmget(key_t key, size_t size, int shmflg); [参数key]:由ftok生成的key标识,标识系统的唯一IPC资源。 [参数size]:需要申请共享内存的大小。在操作系统中,申请内存的最小单位为页,一页是4k字节,为了避免内存碎片,我们一般申请的内存大小为页的整数倍。 [参数shmflg]:如果要创建新的共享内存,需要使用IPC_CREAT,IPC_EXCL,如果是已经存在的,可以使用IPC_CREAT或直接传0。 [返回值]:成功时返回一个新建或已经存在的的共享内存标识符,取决于shmflg的参数。失败返回-1并设置错误码。 4.shmat ( ):挂接共享内存 void *shmat(int shmid, const void *shmaddr, int shmflg); [参数shmid]:共享存储段的标识符。 [参数*shmaddr]:shmaddr = 0,则存储段连接到由内核选择的第一个可以地址上(推荐使用)。 [参数shmflg]:若指定了SHM_RDONLY位,则以只读方式连接此段,否则以读写方式连接此段。 [返回值]:成功返回共享存储段的指针(虚拟地址),并且内核将使其与该共享存储段相关的shmid_ds结构中的shm_nattch计数器加1(类似于引用计数);出错返回-1。 5.shmdt ( ):去关联共享内存 当一个进程不需要共享内存的时候,就需要去关联。该函数并不删除所指定的共享内存区,而是将之前用shmat函数连接好的共享内存区脱离目前的进程。 int shmdt(const void *shmaddr); [参数*shmaddr]:连接以后返回的地址。 [返回值]:成功返回0,并将shmid_ds结构体中的 shm_nattch计数器减1;出错返回-1。 6.shmctl ( ):销毁共享内存 int shmctl(int shmid, int cmd, struct shmid_ds *buf); [参数shmid]:共享存储段标识符。 [参数cmd]:指定的执行操作,设置为IPC_RMID时表示可以删除共享内存。 [参数*buf]:设置为NULL即可。 [返回值]:成功返回0,失败返回-1。 模拟共享内存 我们用server来创建共享存储段,用client获取共享存储段的标识符,二者关联起来之后server将数据写入共享存储段,client从共享区读取数据。通信结束之后server与client断开与共享区的关联,并由server释放共享存储段。 #include <unistd.h> #include <stdlib.

java启动jar包引入外部配置文件

前提: 打出来的jar中已经包含了各个application-xxx.yml文件,jar所在位置也引入了外部的application-test.yml。 目的:运行时,希望使用的时外部 application-test.yml 文件。 使用了以下命令: java -Xms1024m -Xmx2048m -jar /home/test/my-test-app-0.0.1.jar --spring.config.location=./application-test.yml --logging.config=./logback.xml -server my-test-app & 可以启动,但是,使用的时jar包里面的application-test.yml配置,而不是外部的application-test.yml文件。 解决问题: 使用-D命令设置系统属性 java -Xms1024m -Xmx2048m -jar -Dspring.config.location=./application-test.yml /home/test/my-test-app-0.0.1.jar --logging.config=./logback.xml -server my-test-app & 或者: java -Xms1024m -Xmx2048m -jar -Dspring.config.location=./application-test.yml -Dlogging.config=./logback.xml /home/test/my-test-app-0.0.1.jar -server my-test-app & 启动时,如果直接在jar包所在的目录启动, 例如java -jar的方式, 那么会自动加载config或者根目录下的配置文件(properties, yml) 如果使用脚本的启动方式, 那么可能你的执行脚本路径和脚本所在路径不在同一目录, 那么这个时候可以使用绝对路径来配置, 例如: java -jar ./test.jar --spring.config.additional-location=../config/ --spring.profiles.active=dev spring.config.location :会覆盖内部配置参数 spring.config.additional-location :会和内部配置参数互补 问题: 在测试过程种,如果引入的application文件包含spring.profile 属性,会导致引用失败,所以需要删掉这个文件,如果需要使用spring.profile 则需要在启动的脚本中加入这个配置项: java -Xms1024m -Xmx2048m -jar -Dspring.config.location=./application-test.yml -Dlogging.config=./logback.xml /home/test/my-test-app-0.0.1.jar --spring.

kafka:java集成 kafka(springboot集成、客户端集成)

摘要 对于java的kafka集成,一般选用springboot集成kafka,但可能由于对接方kafka老旧、kafka不安全等问题导致kafak版本与spring版本不兼容,这个时候就得自己根据kafka客户端api集成了。 一、springboot集成kafka 具体官方文档地址:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/ 1、加入依赖,spring-boot-starter-web和spring-kafka 的版本号可以看它们依赖的spring版本是否一致,这里pom依赖如下: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.7.9</version> </dependency> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>2.9.6</version> </dependency> 2、添加application.yml配置,具体如下: server: port: 8087 spring: mvc: pathmatch: matching-strategy: ant_path_matcher kafka: bootstrap-servers: 192.168.189.128:9092,92.168.189.128:9093,192.168.189.128:9094 consumer: properties: group: id: boot-kafka 3、发送消息,由于KafkaTemplate是自动装配的,所以只要在spring的bean里注入KafkaTemplate发送消息即可,具体如下: package com.longqi.bootkafka.controller; import com.longqi.bootkafka.entity.MessageParam; import com.longqi.bootkafka.entity.Wrapper; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.kafka.core.KafkaTemplate; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.Valid; /** * <p> * 测试 前端控制器 * </p> * @author LongQi * @since 2021-06-23 */ @Slf4j @RestController @RequestMapping("

操作系统(未完)

进程、线程、协程的区别 进程与线程 进程是资源分配的最小单位,线程是CPU调度的最小单位 做个简单的比喻:进程=火车,线程=车厢线程在进程下行进(单纯的车厢无法运行) 一个进程可以包含多个线程(一辆火车可以有多个车厢)不同进程间数据很难共享(一辆火车上的乘客很难换到另外一辆火车,比如站点换乘)同一进程下不同线程间数据很易共享(A车厢换到B车厢很容易)进程要比线程消耗更多的计算机资源(采用多列火车相比多个车厢更耗资源)进程间不会相互影响,一个线程挂掉可能将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢。而JAVA中不是,线程挂掉不会让进程挂掉)进程可以拓展到多机,进程最多适合多核(不同火车可以开在多个轨道上,同一火车的车厢不能在行进的不同的轨道上)进程使用的内存地址可以上锁,即一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。(比如火车上的洗手间)-“互斥锁”进程使用的内存地址可以限定使用量(比如火车上的餐厅,最多只允许多少人进入,如果满了需要在门口等,等有人出来了才能进去)-“信号量” 线程与协程 为什么需要协程? 我们都知道多线程,当需要同时执行多项任务的时候,就会采用多线程并发执行。拿手机支付举例子,当收到付款信息的时候,需要查询数据库来判断余额是否充足,然后再进行付款。 假设最开始我们只有可怜的10个用户,收到10条付款消息之后,我们开启启动10个线程去查询数据库,由于用户量很少,结果马上就返回了。第2天用户增加到了100人,你选择增加100个线程去查询数据库,等到第三天,你们加大了优惠力度,这时候有1000人同时在线付款,你按照之前的方法,继续采用1000个线程去查询数据库,并且隐隐觉察到有什么不对。 不断增长的线程 几天之后,见势头大好,运营部门开始不停的补贴消费券,展开了史无前例的大促销,你们的用户开始爆炸增长,这时候有10000人同时在线付款,你打算启动10000个线程来处理任务。等等,问题来了,因为每个线程至少会占用4M的内存空间,10000个线程会消耗39G的内存,而服务器的内存配置只有区区8G,这时候你有2种选择,一是选择增加服务器,二是选择提高代码效率。那么是否有方法能够提高效率呢? 我们知道操作系统在线程等待IO的时候,会阻塞当前线程,切换到其它线程,这样在当前线程等待IO的过程中,其它线程可以继续执行。当系统线程较少的时候没有什么问题,但是当线程数量非常多的时候,却产生了问题。一是系统线程会占用非常多的内存空间,二是过多的线程切换会占用大量的系统时间。 线程切换 协程刚好可以解决上述2个问题。协程运行在线程之上,当一个协程执行完成后,可以选择主动让出,让另一个协程运行在当前线程之上。协程并没有增加线程数量,只是在线程的基础之上通过分时复用的方式运行多个协程,而且协程的切换在用户态完成,切换的代价比线程从用户态到内核态的代价小很多。 协程切换 回到上面的问题,我们只需要启动100个线程,每个线程上运行100个协程,这样不仅减少了线程切换开销,而且还能够同时处理10000个读取数据库的任务,很好的解决了上述任务。 协程的注意事项 假设协程运行在线程之上,并且协程调用了一个阻塞IO操作,这时候会发生什么?实际上操作系统并不知道协程的存在,它只知道线程,因此在协程调用阻塞IO操作的时候,操作系统会让线程进入阻塞状态,当前的协程和其它绑定在该线程之上的协程都会陷入阻塞而得不到调度,这往往是不能接受的。 因此在协程中不能调用导致线程阻塞的操作。 线程有最小的内存单位,而且线程的切换由系统进行,由于系统切换调度需要传入上下文,当线程一多的时候,切换来切换去,所以开销大(因为切换和保存恢复上下文)。但是很多场景,上下文可以我们自己搞,系统只会机械的调换,所以能避免一些消耗。而且线程需要系统态,而协程是用户态的,占用小。 区别和实现 进程、线程,都是有内核进行调度,有 CPU 时间片的概念,进行 抢占式调度。 协程(用户级线程)完全由用户自己的程序进行调度(协作式调度),需要协程自己主动把控制权转让出去之后,其他协程才能被执行到。 goroutine 和协程区别 本质上,goroutine 就是协程。 不同的是,Golang 在 runtime、系统调用等多方面对 goroutine 调度进行了封装和处理,当遇到长时间执行或者进行系统调用时,会主动把当前 goroutine 的CPU § 转让出去,让其他 goroutine 能被调度并执行,也就是 Golang 从语言层面支持了协程。Golang 的一大特色就是从语言层面原生支持协程,在函数或者方法前面加 go关键字就可创建一个协程。 线程是操作系统的内核对象,多线程编程时,如果线程数过多,就会导致频繁的上下文切换,这些 cpu时间是一个额外的耗费。 协程,是在应用层模拟的线程,他避免了上下文切换的额外耗费,兼顾了多线程的优点。简化了高并发程序的复杂度。 协程如何实现的? 协程是基于线程的。内部实现上,维护了一组数据结构和 n 个线程,真正的执行还是线程,协程执行的代码被扔进一个待执行队列中,由这 n 个线程从队列中拉出来执行。这就解决了协程的执行问题。那么协程是怎么切换的呢?答案是:golang 对各种 io函数 进行了封装,这些封装的函数提供给应用程序使用,而其内部调用了操作系统的异步 io函数,当这些异步函数返回 busy 或 bloking 时,golang 利用这个时机将现有的执行序列压栈,让线程去拉另外一个协程的代码来执行,基本原理就是这样,利用并封装了操作系统的异步函数。包括 linux 的 epoll、select 和 windows 的 iocp、event 等。

复现Nature子刊Whittaker生物群系图

Whittaker生物群系,也称为生态系统分类法,是基于地理分布和环境条件等因素将地球表面的生态系统分为不同类型的系统。这种分类方法由美国生态学家罗伯特·惠特克(Robert Whittaker)于1962年提出,目的是为了更好地了解和描述生态系统的多样性和功能。 Whittaker使用两个因素对生物群落进行分类:降水和温度 image-20230314233906578 Whittaker生物群系根据气候和植被类型的组合,将地球表面的生态系统划分为五种类型:热带雨林、温带针叶林、温带落叶阔叶林、草原和沙漠。其中,热带雨林分布在赤道附近,气候温暖湿润,植被丰富多样;温带针叶林分布在北半球和南极洲的较高纬度地区,气候寒冷,植被以针叶树为主;温带落叶阔叶林分布在中、高纬度地区,气候四季分明,植被以落叶阔叶树为主;草原分布在中、低纬度地区,气候干燥,植被以草原为主;沙漠分布在低纬度地区,气候干燥,植被稀疏。 下图是一张发表在Nature子刊的图,用于展示不同采样点的气温、降水、高程和所属群落,信息丰富美观。 image-20230314234056033 来看看如何实现 R语言plotbiomes包 用两行代码就能进行一个最简单的实现: library(plotbiomes) whittaker_base_plot() image-20230314234435011 该绘制基于ggplot,可以用ggplot实现相同的结果: library(plotbiomes) library(ggplot2) plot_1 <- ggplot() + # add biome polygons geom_polygon(data = Whittaker_biomes, aes(x = temp_c, y = precp_cm, fill = biome), # adjust polygon borders colour = "gray98", size = 1) + theme_bw() plot_1 Whittaker_biomes是绘制的基本数据,如果考虑修改形状,可以修改该数据: image-20230314234635486 进一步修改颜色,如使用Whittaker_biomes的经典颜色, Ricklefs_colors是包附带的预定义颜色矢量plotbiomes。这些是Ricklefs, RE (2008)中使用的颜色: Ricklefs_colors plot_2 <- plot_1 + # fill the polygons with predefined colors scale_fill_manual(name = "

【Python】【进阶篇】六、Tkinter的Text文本框控件

六、Tkinter的Text文本框控件 Text 文本控件是 Tkinter 中经常使用的控件,与 Entry 控件相比,Text 控件用于显示和编辑多行文本,而 Entry 控件则适合处理单行文本。 Text 文本控件的常用属性 名称说明autoseparators默认为 True,表示执行撤销操作时是否自动插入一个“分隔符”(其作用是用于分隔操作记录)exportselection默认值为 True,表示被选中的文本是否可以被复制到剪切板,若是 False 则表示不允许。insertbackground设置插入光标的颜色,默认为 BLACKinsertborderwidth设置插入光标的边框宽度,默认值为 0insertofftime该选项控制光标的闪烁频频率(灭的状态)insertontime该选项控制光标的闪烁频频率(亮的状态)selectbackground指定被选中文本的背景颜色,默认由系统决定selectborderwidth指定被选中文本的背景颜色,默认值是0selectforeground指定被选中文本的字体颜色,默认值由系统指定setgrid默认值是 False,指定一个布尔类型的值,确定是否启用网格控制spacing1指定 Text 控件文本块中每一行与上方的空白间隔,注意忽略自动换行,且默认值为 0。spacing2指定 Text 控件文本块中自动换行的各行间的空白间隔,忽略换行符,默认值为0spacing3指定 Text 组件文本中每一行与下方的空白间隔,忽略自动换行,默认值是 0tabs定制 Tag 所描述的文本块中 Tab 按键的功能,默认被定义为 8 个字符宽度,比如 tabs=(‘1c’, ‘2c’, ‘8c’) 表示前 3 个 Tab 宽度分别为 1厘米,2厘米,8厘米。undo该参数默认为 False,表示关闭 Text 控件的“撤销”功能,若为 True 则表示开启wrap该参数用来设置当一行文本的长度超过 width 选项设置的宽度时,是否自动换行,参数值 none(不自动换行)、char(按字符自动换行)、word(按单词自动换行)xscrollcommand该参数与 Scrollbar 相关联,表示沿水平方向上下滑动yscrollcommand该参数与 Scrollbar 相关联,表示沿垂直方向左右滑动 Text 文本控件的常用方法 名称说明bbox(index)返回指定索引的字符的边界框,返回值是一个 4 元组,格式为(x,y,width,height)edit_modified()该方法用于查询和设置 modified 标志(该标标志用于追踪 Text 组件的内容是否发生变化)edit_redo()“恢复”上一次的“撤销”操作,如果设置 undo 选项为 False,则该方法无效。edit_separator()插入一个“分隔符”到存放操作记录的栈中,用于表示已经完成一次完整的操作,如果设置 undo 选项为 False,则该方法无效。get(index1, index2)返回特定位置的字符,或者一个范围内的文字。image_cget(index, option)返回 index 参数指定的嵌入 image 对象的 option 选项的值,如果给定的位置没有嵌入 image 对象,则抛出 TclError 异常image_create()在 index 参数指定的位置嵌入一个 image 对象,该 image 对象必须是 Tkinter 的 PhotoImage 或 BitmapImage 实例。insert(index, text)在 index 参数指定的位置插入字符串,第一个参数也可以设置为 INSERT,表示在光标处插入,END 表示在末尾处插入。delete(startindex [, endindex])删除特定位置的字符,或者一个范围内的文字。see(index)如果指定索引位置的文字是可见的,则返回 True,否则返回 False。 下面演示Text 文本控件的属性和方法,代码如下

点云基本概念

文章目录 一、三维数据的表现形式二、点云的概念三、点云的特点四、点云的获取方式激光雷达结构光立体视觉TOF相机 一、三维数据的表现形式 三维数据的表现形式一般分为四种,分别是点云、网格、体素与多视图。 点云是三维空间中点的集合;由N个D维的点组成,当D=3则可表示为三维坐标点(x,y,z) ,当D>3时,可以为(x,y,z)点指定其它的属性(颜色、强度等)。 网格由三角面片和正方形面片组成,其来源于多边形网格。多边形网格由一组带公共顶点的凸多边形表面组成,可近似一个几何表面。 体素从点云发展而来,由三维栅格物体用0和1表征。体素就好比三维空间中的像素点,我们可以把体素网格看作量化的、大小固定的点云。 多视图表示是从不同的模拟视角(虚拟摄像头)获取到的渲染后的多边形网格二维图像集合,从而通过一种简单的方式表现三维几何结构。 二、点云的概念 点云是一种基于三维空间中的点来描述物体形状和特征的表示方法。在计算机视觉、机器人技术、计算机图形学等领域中,点云是一种常见的数据结构,被广泛应用于三维建模、形状分析、目标识别等任务中。 点云可以定义为同一空间参考系下表达目标空间分布和目标表面特性的海量点的集合。 其中同一空间参考系即代表着点云是在三维空间当中的数据;”同一“代表该点云中所有的点都是在同一个坐标系下,而不是分属多个坐标系; 目标空间分布,实际上就是每个点的位置,汇总到一起,构成了点云整体的空间分布; 目标表面特性,实际就是点云中每个点的特性,又称特征,常见的包括颜色、强度、法向等。 三、点云的特点 点云数据是由大量的点组成的一种三维数据结构,其中每个点通常包括其在三维坐标系中的位置信息以及可选的颜色、法向量等属性。点云数据具有许多特点,其中旋转不变性和置换不变性是点云数据中最为重要的两个特点之一。 1. 旋转不变性 旋转不变性是指点云数据在三维空间中的平移旋转不会改变点云数据本身的性质,平移和旋转之后表示的仍然是同一物体。这个特点对于点云数据的处理和分析非常重要,因为在实际应用中,我们很难保证获取到的点云数据的方向和位置是固定不变的,旋转不变性保证了平移旋转不会影响点云的特征提取和识别。为了实现旋转不变性,通常会使用旋转不变特征来描述点云数据,如法向量、曲率等。 2. 置换不变性 置换不变性是指点云数据在点的排列顺序上的变换不影响其描述的物体的形状和特征。也就是说,如果我们对点云数据中的点进行任意排列,得到的点云数据仍然能够描述同一个物体。这个特点在点云数据的处理和分析中也非常重要,因为不同的点云数据可能有不同的点的排列顺序,但它们应该能够描述同一个物体。 为了实现置换不变性,通常会使用基于点的局部坐标系的描述方法,如基于旋转的局部参考系(RF)等。这些方法可以将点云数据中的每个点转换到一个局部坐标系中,从而使得点的排列顺序不再影响点云数据的描述。 四、点云的获取方式 点云的获取方式主要有以下几种: 激光雷达 激光雷达是一种主动型点云获取方式,它通过向物体表面发射激光束,测量激光束反射回来的时间和强度信息,从而得到物体表面的三维点云数据。其原理是利用激光束在传输过程中的反射和回波时间来计算出物体表面的距离信息,再通过旋转激光器或移动激光头的方式扫描整个物体表面,从而获取完整的点云数据。 激光雷达点云的优点是精度高、密度大,能够获取细节丰富、几乎无损的三维点云数据。但缺点是设备成本高、数据处理难度大、对光线条件要求高等。 结构光 结构光也是一种主动型点云获取方式,它通过投射编码的光图案,利用物体表面对光图案的反射来得到物体表面的三维点云数据。其原理是将编码的光图案投射到物体表面上,通过相机捕获光图案在物体表面上的畸变信息,从而得到物体表面的三维坐标信息。 结构光点云的优点是设备成本相对较低、数据处理相对容易、速度快、可以在较暗的环境中工作等。但缺点是精度相对激光雷达较低、对物体表面材质和反射率要求高等。 立体视觉 立体相机是一种被动型点云获取方式,它通过在不同位置拍摄物体的立体图像,计算出物体表面上各点之间的深度差异,从而得到物体表面的三维点云数据。其原理是通过双目或多目相机同时拍摄物体的两个或多个视角,计算出左右图像中对应点的视差信息,从而反推出物体表面上各点的三维坐标信息。 立体相机点云的优点是设备成本相对较低、数据处理相对容易。但缺点是精度相对激光雷达较低、对物体表面材质和反射率要求高、对纹理和颜色等细节信息敏感程度较低等。 TOF相机 TOF(Time of Flight)相机又称飞行时间相机,是一种通过测量光信号飞行时间来确定物体表面距离的成像技术。TOF相机发射一束脉冲光,在物体表面反射后,TOF相机接收到反射光,通过测量光信号从发射到接收的时间差,计算出物体表面的距离信息。 TOF相机的优点是测量速度快,可在短时间内获取大量的点云数据,而且对于物体表面的反射率不敏感,能够适应不同光照和环境条件下的成像。缺点是精度相对较低,受光速等因素影响较大。 此外还有深度相机,RGBD相机等方式,再次不一一列举。 在实际应用中,不同的三维成像技术根据场景的不同需求进行选择。例如,激光雷达常用于自动驾驶、建筑测量、地形测绘、无人机遥感等领域,结构光常用于人脸识别、三维重建等领域,立体相机适用于机器人视觉、室外环境感知等领域,TOF相机常用于室内的人体姿态检测、手势识别等场景,深度相机常用于机器人感知、室内场景重建等领域,而RGBD相机则常用于虚拟现实、自动驾驶等领域。

SAX解析

SAX解析 原文链接https://zhhll.icu/2020/xml/SAX/SAX解析/ SAX解析介绍 由于DOM解析XML的弊端,一种替代的技术就是使用SAX解析。 SAX是基于事件模型的XML解析方式,不需要将整个XML文档加载到内存中,只需加载一部分即可开始解析,在处理过程中不会在内存中记录XML中的数据,占用的资源比较少,当程序处理满足一定条件时,可以立即停止解析,这样不必解析剩余的XML内容。 SAX处理机制 SAX解析主要涉及两个部分:解析器和事件处理器。解析器负责读取XML文档,并向事件处理器发送事件,如元素开始和结束事件;事件处理器则负责对事件做出响应,对传递的XML数据进行处理。 当SAX解析器解析到某类型节点时,会触发注册在该类型节点上的回调函数,继承SAX提供的DefaultHandler来重写相应事件的处理方法并进行注册即可。(事件是由解析器产生并通过回调函数发送给应用程序的,这种模式称为推模式)。 SAX接口介绍 SAXParserFactory 获取SAX解析器的工厂类SAXParser SAX解析器的标准接口 监听器 SAX解析事件一共有四种监听器 EntityResolver 监听实体处理时间的监听器 public interface EntityResolver { public abstract InputSource resolveEntity (String publicId, String systemId) throws SAXException, IOException; } DTDHandler 监听DTD处理事件的监听器 public interface DTDHandler { // 解析DTD符号时触发 public abstract void notationDecl (String name, String publicId, String systemId) throws SAXException; // 解析DTD中的未解析实体时触发 public abstract void unparsedEntityDecl (String name, String publicId, String systemId, String notationName) throws SAXException; } ContentHandler 监听XML文档内容处理事件的监听器

docker挂载目录不同步

docker挂载目录不同步 挂载docker外面的config.yaml文件后,容器里的配置文件一直没有更新。但是每次重启容器后就同步上去了,在测试跟研发服可以这么操作。但是在生产重启一次会有很大的问题,我查了下资料。好像是vi或者vim工具进行编辑文件的时候会修改Inode的值,每次修改后值就跟创建容器的值不匹配了。但是重启容器的时候它好像是根据文件名称进行匹配,所以每次重启后配置文件就能同步。测试了一下使用nano就好像不会修改inode的值,但是这个不大好用。还有一种方法是将配置文件给一个读写的权限 --》 chmod 666 config.yaml。这样在外面修改的时候容器内部的文件也会同步,用reload就可以刷新配置,不会断开服务了。

Yocto系列讲解[理论篇]45 - bb文件中函数实操演示(3)继承自己的class

By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 目录 类函数的灵活继承去除黄色警告 返回总目录:Yocto开发讲解系列 - 总目录 我应该一开始创建一个functions的recipe来专门讲这一系列的内容就好了。我从本篇开始也不迟。 poky]$ cd meta-mylayer/ meta-mylayer]$ cp recipes-example/ recipes-myfunctions -rf #赋值一份,改个名字 meta-mylayer]$ cd recipes-myfunctions/ recipes-myfunctions]$ mv example/ myfunctions recipes-myfunctions]$ mv myfunctions/example_0.1.bb myfunctions/myfunctions_0.1.bb #最终创建 meta-mylayer/recipes-myfunctions/myfunctions/myfunctions_0.1.bb #并将文件中的PN = 'example'改成: PN = 'myfunctions' 后面我就基于这个文件修改。 今天讲类函数的灵活继承 类函数的灵活继承 这节讲的是创建一个自己的class文件,class文件中定义一个do_faa函数,然后在myfunctions的bb文件中继承该class类,如何在myfunctions中重定义do_faa函数,又能调用class中定义的do_faa函数。怎么做呢?通过使用EXPORT_FUNCTIONS语句。 首先我们参考meta/classes/目录中class文件形式,在meta-mylayer/目录中也定义一个自己的class文件,名字叫bar.bbclass,参考如下: poky]$ mkdir meta-mylayer/classes poky]$ vim meta-mylayer/classes/bar.bbclass 好,下面在bar.bbclass文件中定义一个do_faa函数,bar.bbclass文件内容如下: bar_do_faa() { bbplain "I am do_faa function in bar.bbclass" } addtask faa after do_fetch before do_build EXPORT_FUNCTIONS do_faa 等等,你不是说,定义do_faa函数吗?怎么变成了bar_do_faa函数?

python中函数的返回值详解

1.返回值介绍 现实生活中的场景: 我给儿子10块钱,让他给我买包烟。这个例子中,10块钱是我给儿子的,就相当于调用函数时传递到参数,让儿子买烟这个事情最终的目标是,让他把烟给你带回来然后给你对么,,,此时烟就是返回值 开发中的场景: 定义了一个函数,完成了获取室内温度,想一想是不是应该把这个结果给调用者,只有调用者拥有了这个返回值,才能够根据当前的温度做适当的调整 综上所述: 所谓“返回值”,就是程序中函数完成一件事情后,最后给调用者的结果 2.带有返回值的函数 想要在函数中把结果返回给调用者,需要在函数中使用return 如下示例: def add2num(a, b): c = a+b return c 或者 def add2num(a, b): return a+b 3.保存函数的返回值 在本小节刚开始的时候,说过的“买烟”的例子中,最后儿子给你烟时,你一定是从儿子手中接过来 对么,程序也是如此,如果一个函数返回了一个数据,那么想要用这个数据,那么就需要保存 保存函数的返回值示例如下: #定义函数 def add2num(a, b): return a+b #调用函数,顺便保存函数的返回值 result = add2num(100,98) #因为result已经保存了add2num的返回值,所以接下来就可以使用了 print (result) 结果: 198 4.四种函数的类型 函数根据有没有参数,有没有返回值,可以相互组合,一共有4种 无参数,无返回值无参数,又反悔有参数,无返回值有参数,有返回值 1.无参数,无返回值的函数 此类函数,不能接收参数,也没有返回值,一般情况下,打印提示灯类似的功能,使用这类的函数 def printMenu(): print('--------------------------') print(' xx涮涮锅 点菜系统') print('') print(' 1. 羊肉涮涮锅') print(' 2. 牛肉涮涮锅') print(' 3. 猪肉涮涮锅') print('--------------------------') 结果: 2.无参数,有返回值的函数 此类函数,不能接收参数,但是可以返回某个数据,一般情况下,像采集数据,用此类函数 # 获取温度 def getTemperature(): #这里是获取温度的一些处理过程 #为了简单起见,先模拟返回一个数据 return 24 #小编创建了一个Python学习交流群:725638078 temperature = getTemperature() print('当前的温度为:%d'%temperature) 结果: