MyBatis
缓存可以极大的提升查询效率。
MyBatis系统中默认定义两级缓存(一级缓存和二级缓存)。
一、两级缓存
1、一级缓存:(本地缓存):sqlSession级别的缓存。一级缓存是一直开启的;sqlSession级别的一个Map。
与数据库同一次会话期间查询到的数据会放在本地缓存中
以后如果需要获取相同的数据,直接从缓存中拿,没必要再去查询数据库;
一级缓存失效情况(没有使用到当前一级缓存的情况,效果就是,还需要再向数据库发出查询):
1、sqlSession不同。
2、sqlSession相同,查询条件不同。(当前一级缓存中还没有这个数据)
3、sqlSession相同,两次查询之间执行了增删改操作(这次增删改可能对当前数据有影响)
4、sqlSession相同,手动清除了一级缓存(缓存清空)
2、二级缓存:(全局缓存):基于namespace级别的缓存:一个namespace对应一个二级缓存:
工作机制:
1、一个会话,查询一条数据,这个数据就会被放在当前会话的一级缓存中;
2、如果会话关闭;一级缓存中的数据会被保存到二级缓存中;新的会话查询信息,就可以参照二级缓存中的内容。
3、sqlSession=EmployeeMapper=>Employee
DepartmentMapper===>Department
不同的namespace查出的数据会放在自己对应的缓存中(Map)
效果:数据会从二级缓存中获取
查出的数据都会被默认先放在一级缓存中。
只有会话提交或者关闭以后,一级缓存中的数据才会转移到二级缓存中。
使用步骤:
1)、开启全局二级缓存配置:mybatis默认开启二级缓存,还是要在配置文件中显式的开启
在配置文件mybatis-config.xml的setting将其开启
//显式的指定每个我们需要更改的配置的值,即使他是默认的。防止版本更新带来的问题
2)、去mapper.xml中配置使用二级缓存: 在哪个mapper文件中使用cache标签,那个mapper中有二级缓存
在mapper标签中写标签。
<!-- eviction:缓存的回收策略: LRU==最近最少使用:移除最长时间不被使用的对象。 FIFO==先进先出:按对象进入缓存的顺序来移除它们。 SOFT==软引用:移除基于垃圾回收器状态和软引用规则的对象。 WEAK==弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。 默认是LRU。 flushInterval:缓存刷新间隔 缓存多长时间清空一次,默认是不清空,设置一个毫秒值 readOnly:是否只读; true:只读;mybatis认为所有从缓存中获取数据的操作都是只读操作,不会修改数据。 mybatis为了加快获取速度,直接就会将数据在缓存中的引用交给用户。不安全,速度快。 false:非只读;mybatis觉得获取的数据可能会被修改。 mybatis会利用序列化&反序列化的技术克隆一份新的数据给你。安全,速度慢。默认为false。 size:缓存存放多少元素; type:指定自定义缓存的全类名; 实现Cache接口即可; --> <cache></cache> 3)、我们的POJO需要实现序列化接口
两个不同的sqlSession,开启二级缓存之后。第一次会话关闭之后,第二次查询时直接在二级缓存中取。
3、缓存有关的设置以及属性
和缓存有关的设置/属性:
1)、cacheEnabled=true:
=false:关闭缓存(关闭二级缓存)(一级缓存一直可用)
2)、每个select标签都有useCache=“true”:
=false:不使用缓存(一级缓存依然可以使用,二级缓存不使用)
3)、每个增删改标签:flushCache=“true”:增删改执行完成后就会清除缓存(一级二级都会清除)
测试:flushCache=“true”:一级缓存就清空了;二级缓存也会被清空。
在select标签中默认flushCache=false:不清缓存,如果改为true,每次查完就会清缓存。
4)、sqlSession.clearCache():只是清除当前sqlSession的一级缓存; 5)、在全局配置文件的settings标签中localCacheScope:本地缓存作用域:(一级缓存SESSION);当前会话的所有数据保存在会话缓存中;
STATEMENT:可以禁用一级缓存;
4、缓存原理图示
Cache接口:
mybatis的缓存就是一个小Map
❄️作者介绍:奇妙的大歪❄️
🎀个人名言:但行前路,不负韶华!🎀
🐽个人简介:云计算网络运维专业人员🐽
前言
首先零基础是能学python的,很多编程大神入门之前都选择先学习Python,所以想学就大胆去学吧,没学之前谁不是零基础,就算是现在才下定决心学也不怕,学习Python什么时候都不算晚。
零基础如何学好python,作为一个学了python两三年的过来人,我当初也是从0开始一路摸索过来的,这里给想学python的小白们分享一点我的学习心得。
目录
一.重新认识函数
二.开始创建函数
三.需要注意的是
四.传递参数与参数类型
五.设计自己的函数
一.重新认识函数 我们先不谈Python 中的函数定义,因为将定义放在章节的首要位置,这明显就是懒得把事情讲明白的做法,相信你在阅读其他教材时对这点也深有体会。所以我要说的是,经过第一章的阅读与训练,其实你早已掌握了函数的用法:
print是一个放入对象就能将结果打印的函数 input 是一个可以让用户输入信息的函数len是一个可以测量对象长度的函数
int 是一个可以将字符串类型的数字转换成整数类型的函数 通过观察规律其实不难发现,Python 中所谓的使用函数就是把你要处理的对象放到一个名字后面的括号里就可以了。简单的来说,函数就是这么使用,可以往里面塞东西就得到处理结果。这样的函数在 Python 中还有这些: 以最新的3.50版本为例,一共存在68个这样的函数,它们被统称为内建函数(Built-in Functions)。之所以被称之为内建函数,并不是因为还有“外建函数”这个概念,内建的意思是这些函数在3.50版本安装完成后你就可以使用它们,是“自带”的而已。千万不要为这些术语搞晕了头,随着往后学习,我们还能看见更多这样的术语,其实都只是很简单的概念,毕竟在一个专业领域内为了表达准确和高效往往会使用专业术语。
现在你并不必急着把这些函数是怎么用的都搞明白,其中一些内建函数很实用,但是另外一些就不常用,比如涉及字符编码的函数ascii(),bin(),chr()等等,这些都是相对底层的编程设计中才会使用到的函数,在你深入到一定程度的时候才会派的上用场。
附上 Python官网中各个函数介绍的链接:python函数链接,有兴趣深入了解的话可以看一眼。
二.开始创建函数 我们需要学会使用已有的函数,更需要学会创建新的函数。自带的函数数量是有限的,想要让 Python 帮助我们做更多的事情,就要自己设计符合使用需求的函数。创建函数也很简单,其实我们在多年前的初中课堂上早已掌握了其原理。
先试着在命令行/终端中进入 Python环境,输入这样的公式: 看着有点眼熟吧?第一个是数学的梯形计算公式,而第二个是物理的摄氏度与华氏度的转换公式。 函数是编程中最基本的魔法,但同时一切的复杂又都被隐含其中。它的原理和我们学习的数学公式相似,但是并不完全一样,等到后面一点你就知道我为什么这么说了。这里面先介绍几个常见的词:
🌞def(即 define,定义)的含义是创建函数,也就是定义一个函数。
🍎arg(即argument,参数)有时你还能见到这种写法:parameter,二者都是参数的意思但是稍有不同,这里不展开说了。
❄️return 即返回结果。
好,现在我们读一遍咒语:Define a function named 'function’which has two arguments:arg1 and arg2, returns the result--'Something’是不是很易读很顺畅?代码的表达比英文句子更简洁一点:
三.需要注意的是
🐼def 和return 是关键字(keyword),Python就是靠识别这些特定的关键字来明白用户的意图,实现更为复杂的编程。像这样的关键字还有一些,在后面的章节中我们会细致讲解;
🎀在闭合括号后面的冒号必不可少,而且非常值得注意的是你要使用英文输入法进行输入,否则就是错误的语法,如果你在IDE中输入中文的冒号和括号,会有这样的错误提示: 🍩如果在IDE中冒号后面回车(换行)你会自动地得到一个缩进。函数缩进后面的语句被称作是语句块(block ),缩进是为了表明语句和逻辑的从属关系,是 Python 最显著的特征之一。很多初学者会忽视缩进问题,导致代码无法成功运行,在这里需要特别注意。
现在我们看一下之前提到的摄氏度转化公式,按照上面定义函数的方法来实现一遍。我们把摄氏度转化定义为函数fahrenheit_Converter(),那么将输入进去的必然是摄氏度(Celsius)的数值,我们把 C 设为参数,最后返回的是华氏度(fahrenheit)的数值,我们用下面的函数来表达,输入代码:
def fahrenheit_converter(C): fahrenheit = C * 9/5 + 32 return str(fahrenheit) + '˚F' 注:计算的结果类型是int,不能与字符串“下”相合并,所以需要先用str()函数进行转换
1. 适配器模式概述: 适配器模式是一种结构型设计模式,它允许将一个类的接口转换成客户端所期望的另一个接口。适配器模式的主要目的是解决两个不兼容接口之间的接口转换问题,使得原本由于接口不匹配而无法工作的类可以协同工作。
在现实生活中,适配器也是常见的一种工具,例如电源适配器可以将不同国家的电源插头转换成我们所需要的标准插头。同样,适配器模式在软件开发中起到了类似的作用。
适配器模式的核心思想是创建一个适配器类,该适配器类实现了客户端期望的目标接口,并持有一个对被适配者对象的引用。适配器类通过调用被适配者对象的方法来实现目标接口的方法,从而完成接口的适配。
2. 适配器模式结构: 使用类图或示意图展示适配器模式的结构,包括目标接口(Target)、适配器(Adapter)、被适配者(Adaptee)等组成部分。
适配器模式常见的实现方式:
类适配器 类适配器使用继承来适配接口,它同时继承了目标接口和被适配者类,通过重写目标接口的方法并调用被适配者类的方法来实现适配。
对象适配器 对象适配器使用组合关系来适配接口,它持有一个被适配者对象的引用,在适配器类中调用被适配者对象的方法来实现适配。
接口适配器 是一种特殊的适配器模式,它用于解决接口过多或接口不匹配的问题。接口适配器模式通过定义一个抽象类来实现目标接口,并提供默认的空方法实现,这样客户端只需实现自己感兴趣的方法,而无需实现全部接口方法。
3. 适配器示例代码: 3.1 类适配器: 被适配类Adaptee:
/** * 被适配的类 */ public class Voltage220v { public int output220v() { int src = 220; System.out.println("电压=" + src + "伏"); return src; } } 目标类:
public interface Voltage5v { public int output5v(); } 适配类Adapter:
/** * 适配类 * extends:单继承src,局限性 * VoltageAdapter类:暴露了Voltage220v(src)类output220v()方法,但是灵活性增强了 */ public class VoltageAdapter extends Voltage220v implements Voltage5v{ @Override public int output5v() { int src = output220v(); int dst = src / 44; return dst; } } 测试:
文章目录 概述监控Linux系统的CPU和内存占用情况查看CPU占用情况top命令mpstat命令 查看内存占用情况free命令top命令 总结 概述 下面是一篇关于Linux中查看CPU和内存占用的相关博文,其中包括详细的解释和示例命令,以帮助您了解如何在Linux系统中监控CPU和内存的使用情况。
监控Linux系统的CPU和内存占用情况 在Linux系统中,我们经常需要查看系统的CPU和内存占用情况,以便了解系统的性能和资源使用情况。本篇博文将介绍一些常用的命令和工具,帮助您监控Linux系统的CPU和内存占用。
查看CPU占用情况 top命令 top命令是一个常用的系统监视工具,它可以实时显示系统的各项性能指标,包括CPU占用情况。以下是使用top命令查看CPU占用的示例:
top 在top命令的输出中,可以看到当前系统的总体CPU使用情况、各个进程的CPU占用情况,以及其他系统信息。按下键盘上的"1"键,可以查看每个CPU核心的使用情况。
mpstat命令 mpstat命令用于显示每个处理器的平均性能统计信息。它可以提供更详细的CPU占用信息,包括每个CPU核心的使用情况和平均负载。以下是使用mpstat命令查看CPU占用的示例:
mpstat -P ALL 该命令将显示每个CPU核心的使用情况和其他性能指标。
查看内存占用情况 free命令 free命令用于查看系统的内存使用情况,包括总内存、已使用内存、空闲内存等信息。以下是使用free命令查看内存占用的示例:
free -h 该命令将以人类可读的方式显示内存使用情况,以便更直观地了解系统的内存状态。
top命令 除了查看CPU占用情况,top命令也可以用于查看内存占用情况。在top命令的输出中,可以看到当前系统的内存使用情况,包括已使用内存、可用内存、缓存和缓冲区等信息。
总结 本篇博文介绍了一些常用的命令和工具,帮助您在Linux系统中监控CPU和内存占用情况。通过这些命令,您可以及时了解系统的性能状况,及时采取措施优化系统资源的使用。
希望这篇博文对您有所帮助!
怎么编写接口测试用例?接口测试用例如何编写?看到许多这样的问题,大家都知道编写接口测试用例是接口测试的重要组成部分,它决定了测试的质量和可靠性。因此,程序员必须编写高质量的接口测试用例,以确保接口在生产环境中能够正常运行。
编写接口测试用例的步骤如下:
一、理解接口需求 在编写接口测试用例之前,程序员必须完全理解接口的需求。他们需要详细了解接口的设计,包括功能、输入、输出等。程序员还需要详细了解接口的使用场景,以便编写出能够覆盖所有需求的测试用例。
二、确定测试策略 程序员需要根据接口的需求和使用场景,确定测试策略。他们需要考虑到测试的目标,例如是否要测试接口的性能、稳定性等。程序员还需要确定测试用例的类型,例如是否要编写正确性测试用例、边界测试用例等。
三、编写测试用例 在确定了测试策略后,程序员可以开始编写测试用例。他们需要考虑到接口的所有需求,编写出充分覆盖所有功能的测试用例。下面是一些有助于编写测试用例的技巧:
确定边界值:接口的边界值往往是关键的测试点,因为它们涉及到系统的极限性能。例如,对于数字类型的字段,可以考虑最大值、最小值、超出范围的值等。编写正常和异常用例:除了正常的请求-响应模式,还应该考虑输入错误、系统故障等异常情况。利用现有的数据:现有的数据库、以前的版本等可以作为测试用例的数据源。编写可重复的测试用例:避免手动编写的测试用例结果因人为原因而不同,尽量编写可重复的测试用例。 四、执行接口测试用例 执行接口测试用例时,应当选择一个可靠的测试工具,并且在测试用例执行完毕之后,对比测试结果与预期结果,如果不一致,应该尽早发现并修复。
需要注意的是,在执行接口测试用例之前,需要保证所有相关的环境都已经准备好,并且接口的性能不应该有任何影响。
五、接口测试报告 执行完接口测试用例之后,应当生成一份接口测试报告,这份报告应该包括测试用例的执行结果,测试用例的执行情况,以及接口的性能数据等内容。
此外,报告还应该包括一些对接口测试的总结和建议,例如:在接口测试过程中,发现的问题和改进的建议,以及接口测试的优化方案等。
六、维护接口测试用例 随着系统的不断更新和变化,接口测试用例也应该随之更新和变化。因此,维护接口测试用例是非常重要的,如果不及时维护,可能会导致接口测试用例失。所以我们需要一些软件来辅助维护接口及接口测试用例。
那就不得不说以一体化 API 管理为产品理念的工具——Apifox,它既可以作为 API 接口文档管理工具使用,也可以结合 API 开发调试、API Mock 以及 API 自动化测试的实践,来高效地管理维护接口测试用例。
尤其是自动化测试功能,Apifox 可以快速创建接口测试用例,可以通过推拉拽的方式修改用例顺序,支持自定义设置循环、判断等流程控制条件,满足多样化测试场景。还可以使用测试数据帮助模拟真实场景。
自动化测试运行完成后还会生成测试报告,可以查看所有接口运行的情况,包括成功与失败。每个接口还可以单独查看接口的具体运行情况,针对接口单独运行测试,帮助测试人员准确定位问题。测试报告还支持多方式导出,非常的贴心了。
最后 Apifox 对于测试团队是非常实用的工具,可它的产品理念是“ all in one”,除了自动化测试以外,API 开发调试、API Mock、API 文档也是做的非常好的,非常适合开发团队协作使用,而且它是免费使用!根本不收钱!这还要啥自行车啊!冲就完了!
最后:下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取【保证100%免费】
整套资料获取
如何选择科研可视化的图表 Highlights 一张漂亮的配图能让论文增色不少,但现在的图表类型越来越丰富,学者们很难选择合适的绘图类型进行可视化。
随着大数据和云计算的发展,我们很容易就能获取大量的数据,但是将这些数据美观地展示出来不是一件容易的事情。
本文帮助大家选取可视化的类型,并提供丰富的源码。
可视化的要点 科研数据可视化的技巧和要点有很多,其中包括:选择合适的图表类型、设计易于理解的图表、使用颜色和字体来强调重点、避免使用过于复杂的图表。
今天来讲讲如何选择合适的图表和设计易于理解的图表
常用的可视化工具,如Matplotlib、Seaborn、ggplot、Basemap、Matlab、Origin、cartopy、和ProPlot等
建议掌握一种工具绘图(Origin、Excel等)、一种图层语言(ggplot,seaborn)、一种地理绘图(cartopy、proPlot)即可
根据目的选择图表 拿到数据,首先选择合适的图表。首先是按用途选择:
一个非常经典的 Chart Suggestions---A Thought-Starter by Andrew Abela
(所有的PDF资源整合到了文末领取)
image-20230403111725881 这个 Chart Suggestions 从四个维度提供了可供选择的类型,而主要是根据你想展示的内容进行的
更细致的图表如图(文末领取):
poster 这张表(文末领取)按照更多的维度进行了更细致地分类,根据你的展示目的选择合适的可视化方式
从可视化宇宙中查看排名 Adioma 和 Google News Lab提供了一个可视化宇宙,清楚地展示了人们选择图表的倾向、工具和参考书:
http://visualizationuniverse.com/
image-20230403112350703 可以根据受欢迎程度来选择你的图表:
image-20230403112436187 包括很多可视化的学习资料:
image-20230403112459438 根据数据选择图表 有时候可视化不取决于我们的目的,而取决于我们有什么样的数据,这时候数据类型就很重要。
可以参考下面这张表:
img 有时根据目的选择最合适和最方便的图表很复杂。上图可以从数据驱动的角度帮助您找出应该使用哪种类型的图表。您所需要的只是获得有关您的数据的信息。
之后,通过回答给定的问题。这些问题将作为一个框架,提供有关合适图表的建议,帮助制作和选择一个引人入胜的图表。
我们信息图的分支是分层构建的,从顶部开始。首先,回答你是否有一个或多个变量。如果你只有一个变量向左移动。然后,决定这个变量是否有序。因此,如果只有一个变量,可以从以下类型中选择图表:
折线图、面积图、箱型图、直方图、密度图
现在,让我们看看右侧。起点保持不变——定义变量的特征。如果特征不相似,那么我们向左移动并定义变量是否为有序数据。如果不是,我们应该使用散点图;如果是——从面积图或连接的散点图中选择。
另一个参考工具是DataVizProject
https://datavizproject.com/#
image-20230403113131608 优点是每种图含有数据格式,可以根据您的数据选择合适的图表:
如下图的Stacked Bar Chart至少需要一个2维的数据
image-20230403113246251 此外还可以在Examples中找到相关的例子和可能的源代码。
还可以根据输入数据的类型找到适合的图表:
image-20230403113423782 寻找可视化的代码 使用交互式的From Data to Viz
https://www.data-to-viz.com/
image-20230403113618261 点击Explore选择合适的分类和图表: image-20230403113710924 点击心仪的图表,再点击你熟悉的编程语言获得代码:
安装环境 Anaconda安装 首先安装python环境,推荐Anaconda+jupyter,而不是Pycharm
1.首先下载Anaconda:
image-20221221170834818 https://www.anaconda.com/products/distribution#download-section
2.下载好打开Anaconda Prompt
image-20221221171359765 3.配置一下镜像源,添加阿里镜像
conda config --set show_channel_urls yes
然后就在C:\Users\用户名 这里找到.condarc
记事本打开修改为:
channels:
- defaults
show_channel_urls: true
default_channels:
- http://mirrors.aliyun.com/anaconda/pkgs/main
- http://mirrors.aliyun.com/anaconda/pkgs/r
- http://mirrors.aliyun.com/anaconda/pkgs/msys2
custom_channels:
conda-forge: http://mirrors.aliyun.com/anaconda/cloud
msys2: http://mirrors.aliyun.com/anaconda/cloud
bioconda: http://mirrors.aliyun.com/anaconda/cloud
menpo: http://mirrors.aliyun.com/anaconda/cloud
pytorch: http://mirrors.aliyun.com/anaconda/cloud
simpleitk: http://mirrors.aliyun.com/anaconda/cloud
再清除索引缓存:
conda clean -i 创建一个深度学习的环境(避免不同的包相互冲突,我目前设置了四个环境:geemap,绘图,地理库和深度学习)
# 1.查看有哪些可安装的python版本
conda search --full-name python
# 2.创建新环境DL
conda create --name DL python=3.8.12
# 如果想删除环境采用以下操作
# conda remove -n DL --all
目录
一、HashMap中的一些静态成员变量
1、DEFAULT_INITIAL_CAPACITY
2、MAXIMUM_CAPACITY
3、DEFAULT_LOAD_FACTOR
4、TREEIFY_THRESHOLD
5、UNTREEIFY_THRESHOLD
6、MIN_TREEIFY_CAPACITY
二、HashMap中的构造方法
1、HashMap()
2、HashMap(int)
3、HashMap(int,float)
4、HashMap(Map)
三、HashMap中的put方法
1、初始化底层数组为空的数组容量
2、插入元素
2.1 当前数组下标为空
2.2 当前数组下标不为空
3、数组扩容
一、HashMap中的一些静态成员变量 1、DEFAULT_INITIAL_CAPACITY 表示HashMap底层数组的默认容量是1 << 4,即2^4=16。
2、MAXIMUM_CAPACITY 表示HashMap底层数组的最大容量是1 << 30,即2^30。
3、DEFAULT_LOAD_FACTOR 表示HashMap的默认负载因子的值是0.75。
4、TREEIFY_THRESHOLD 表示底层数组中的链表树化的条件之一:链表中至少有8个节点。
5、UNTREEIFY_THRESHOLD 表示底层数组中的红黑树解树化的条件:树中节点少于6个的时候退化成链表。
6、MIN_TREEIFY_CAPACITY 表示底层数组中的链表树化的条件之一:底层数组的容量至少为64。
二、HashMap中的构造方法 1、HashMap() 无参的构造方法仅仅指定了负载因子的大小为默认的0.75,并没有初始化底层数组的容量,所以当我们调用无参的构造方法构造一个HashMap,此时底层的数组为NULL,容量为0。 2、HashMap(int) 带有一个参数的构造方法可以用来指定底层数组的初始容量,但实际上调用的是下面带有2个参数的构造方法↓
3、HashMap(int,float) 构造一个底层数组初始容量为initialCapacity, 负载因子为loadFactor的HashMap,如果initialCapacity小于0或loadFactor小于等于0,就会抛出一个IllegalArgumentException异常,如果initialCapacity大于2^30,则初始容量为2^30。
继续追踪tableSizeFor(initialCapacity),看一下数组的初始容量会被设置为多少:
tableSizeFor(int cup)方法会将我们传进来的initialCapacity经过一系列位运算,最后的返回值我们可以看最上面的那一行注释,它最后会返回一个最接近initialCapacity并且大于initialCapacity的2的次方的数,举个栗子,如果给定的initialCapacity是10,那么会返回16;如果initialCapacity是25,那么会返回32……
那么问题来了,为什么要这样做呢?为什么不直接initialCapacity返回呢?
这样做是为了在put方法中更快速地计算数组下标。
4、HashMap(Map<? extends K, ? extends V>) 这个构造方法会把传进来的Map构造为一个新的HashMap,映射关系与原来的Map相同,底层数组使用默认负载因子(0.75)和足够容纳指定Map中的映射的初始容量创建。
三、HashMap中的put方法 我们来看一下源码中是如何建立key-vauel映射关系的:
它会首先计算key的哈希值,然后将哈希值,key,value传入putVal方法中。
追踪putVal方法:
内容有点多,我们逐条来看:
1、初始化底层数组为空的数组容量 第一行定义了一个Node<K,V>类型的tab数组,p节点,和两个整型变量n、i。
然后让tab指向底层数组table,判断tab是否为空,或者容量是否为0,满足以上条件之一,就会调用resize()方法对数组进行初始化容量的操作,然后再计算数组的长度。
刚才无参的构造方法并没有初始化底层数组,那么我们追踪一下resize()方法,看一下最后会将底层数组的容量初始为多少。
追踪resize方法:
也就是说,如果调用无参的构造方法后,第一次进行put操作时,会将底层的数组容量初始为默认的容量:16
1、将word文件另存为rtf文件
2、用记事本打开刚刚保存的rtf文件
3、在记事本里查找password
4、将password后面一行的代码全部删除
5、删除后,在passwordhash后面,输入nopassword ,保存
6、用word打开rtf
7、在审阅-限制编辑,选择右下角停止保护,即接触限制
一、准备工作
1、在Linux系统下载环境配置命令
1、$ yum install -y gcc-c++ (Linux安装组件)
2、$ yum install -y pcre pcre-devel
3、$ yum install -y zlib zlib-devel
4、$ yum install -y openssl openssl-devel
5、$ yum install -y vim 修改背景颜色
6、$ yum install -y wget 安装wget命令,可以通过wget命令下载需要的文件
7、$ yum install -y lrzsz 安装上传文件命令
2、在根目录下新建文件夹soft,用于存放之后的JDK、Tomcat等相关软件3、此处提供一些Linux中常用命令
1. cd / 回到根目录
2. cd /usr 切换usr目录 (usr为存放下载软件的目录)
3. cd .. /.. 返回两级
4. pwd 查看绝对路径
5. ls 查看文件夹中的文件 ll 列表信息查看文件夹中文件
一、问题背景 由于博主需要在自己的虚拟机里使用docker-compose文件生成docker 容器,所以每次一旦ip地址改了,那么docker.yaml文件就要改,这也太麻烦了,于是设置一个静态ip固定一下,省的以后一直变。亲测成功,现在分享一下!
二、本机网络设置 进入控制面板->网络和Internet->更改适配器选项,进入到这个页面:
找到这个VMnet8,然后右键属性->找到其中有一个IPv4的设置项:
点击 进去后进行设置:
三、设置VMware 点击VMware 编辑->虚拟网络编辑器:
点击更改设置:
同时这里要设置一下NAT设置 :
四、设置具体的虚拟机(我的是Ubuntu18.04) 用NAT模式进入哈!
打开虚拟机: 因为Ubuntu17版本后已经不用在/etc/network/interfaces中设置静态ip了
改用netplan方式设置,所以我们要找到netplan的配置文件
他在/etc/netplan/中,每个虚拟机的文件名不同,所以必须要去自己的虚拟机下找到这个文件:
我的机器里叫这个名字,接下来我们修改这个文件:
sudo vim /etc/netplan/01-network-manager-all.yaml 文件夹中这样设置:
# Let NetworkManager manage all devices on this system network: version: 2 renderer: NetworkManager ethernets: ens33: #网卡名字 dhcp4: no #禁用DHCP addresses: [192.168.235.132/24] #设置本机IP和掩码 gateway4: 192.168.235.1 #设置v4网关 nameservers: addresses: [192.168.235.1, 8.8.8.8, 114.114.114.114] #设置DNS 设置好后:wq!保存
设置后重启网卡
sudo netplan apply 然后查看是否配置成功
ip addr 可以看到确实配置成功
接着保险点,我们可以reboot重启虚拟机。
重启后我们ping一下百度看看:
成功! =========================================================================
5月23日,国家标准化管理委员会发布了GB/T 42582-2023《信息安全技术 移动互联网应用程序(App)个人信息安全测评规范》,该国家标准将于2023年12月1日正式施行。江苏通付盾信息安全技术有限公司参与了该标准的起草。
当前,移动互联网应用程序(App)已经深入人们的日常工作与生活。在使用过程中,各类App采集了大量的用户个人信息,出现了个人信息被过度收集或泄露等个人信息安全问题,引起了社会大众和政府监管的普遍关注。
本标准规定了针对App个人信息安全进行测评的测评要求、测评方法和判断准则,适用于指导App运营者、监管部门、第三方测评机构的相关测评人员对App的个人信息安全进行检测评估。本标准主要技术内容:结合App实现自身业务功能的过程中涉及的个人信息收集、传输、存储、处理、交换、销毁等环节,提出App个人信息安全测评的测评要求、测评指标、测评方法和测评判定准则,为App运营者、测评机构、监管机构等在对App的个人信息安全进行测评时提供判断依据。
多年来,通付盾专注数字安全领域,凭借持续不断的技术创新和积累,自主研发核心技术,参与制定多项国家和行业标准,具有自主知识产权以及多项发明专利。目前累计申请发明专利190余项,已授权发明专利90余项,拥有150余项软件著作权,覆盖网络安全、人工智能、区块链等领域。成立十余载通付盾始终不忘初心,坚守品质,重视产品质量、打磨产品各个环节,以高品质产品服务客户。未来,通付盾将继续坚守在数字化技术攻坚战前沿,加强技术攻关,做硬核的核心技术攻关者,为我国网络安全建设以及数字化转型贡献自己的力量!
问题描述 使用MMdetection复现论文swin Transformer,显示错误:
ERROR:The testing results of the whole dataset is empty
与此同时,各项评价指标如AP,AR结果趋于零,F1值变成-1,loss与grad_norm爆炸增加,具体情形如下图:
问题分析 看到报错的第一眼,猜测可能是数据集的问题,所以检查了数据集的路径,然后检查了数据集里面是否有图片,但经过一番验证,排除了这种可能性。如果数据集本身有问题,代码一开始就无法运行起来,因为mmdet一定会报错,而且报错内容是:找不到数据集或者说找不到某张图片。
再仔细观察报错:ERROR:The testing results of the whole dataset is empty,拿不到测试结果,结合爆炸的loss与grad_morm,我有理由怀疑是梯度爆炸或者梯度消失所导致的。有了这个猜测,我回头审视自己的代码,最有可能导致梯度爆炸的超参数就是学习率lr,是不是我自己设置的学习率lr不合适?
学习率是啥?
学习率是梯度下降多次迭代过程中,用来控制模型学习进度的超参数。可以这么理解,学习率大就学的快(梯度下降块),学习率小就学得慢,但学习率并非越大越好,学习率过大,容易造成梯度爆炸或者消失。
解决办法 MMdetection默认的学习率,大多都是0.02,如果不刻意更改,模型会使用这个学习率去训练,swin Transformer没办法在lr=0.02条件下训练,将学习率更改为论文设定的0.0001,模型就正常训练。
在MMdetection中,学习率的调整是在目录:configs/base/schedules/schedule_1x.py文件中:
————————————————
原文链接:https://blog.csdn.net/fengbao24/article/details/127258699
用re模块写正则表达式匹配文本 代码中的test.txt 是利用requests请求得到的html文本
https://www.maoyan.com/board/4?offset=0
import json import re import requests def test_re(): url = 'https://pz.wendu.com/' response = requests.get(url) data = response.text # print(data) res = re.findall(r'<a target=.*?Chatpre.*?>(.*?)</a>', data) print(res) def test_re2(): with open('test.txt', 'r', encoding='utf-8') as f: content = f.read() f.close() pattern = re.compile( r'<dd>.*?board-index.*?>(.*?)</i>.*?data-src="(.*?)".*?name"><a.*?>(.*?)</a>.*?"star">(.*?)</p>.*?"releasetime">(.*?)</p>.*?score"><i.*?>(.*?)</i>.*?fraction">(.*?)</i>.*?</dd>', re.S) items = re.findall(pattern, content) for item in items: # print(item) yield { 'index': item[0], 'data-src': item[1], 'title': item[2], 'star':str(item[3]).strip()[3:], 'time':str(item[4]).strip()[5:], 'score':str(item[5])+str(item[6]) } if __name__ == '__main__': for item in test_re2(): print(item) with open('result.
在ArcMap中打开shp 我用的是ArcMap 10.8.1
1、点击文件菜单-添加数据-添加数据
2、选择shp文件所在目录
点击连接到文件夹,在本地找到shp文件所在的目录
3、打开数据属性表
鼠标右键图层,点击打开属性表
4、标注属性
把属性表的值标注在图中
5、编辑标注属性
修改标注的颜色、大小
修改标注要素的大小和颜色
一、python对象转geojson 工作中遇到需要把经纬度坐标在地图上进行可视化,需要写成geojson格式的文件。笔记记录一下学习过程。
import pandas import geojson path = r'关联场站的公交首末站.xlsx' def convert_point_string2_list(point_string): point_list = [] point_arr = str(point_string).split(';') for point in point_arr: tmp = point.split(',') if len(tmp) == 2: point_list.append([float(tmp[0]), float(tmp[1])]) return point_list data_f = pandas.read_excel(path) #把每一行数据中的点和多边形转换成geojson的对象 feat_list = [] for item in data_f.values: ''' item[0]:站点名称 item[1]:经纬度字符串 item[2]:公交线路 item[3]:场站名称 item[4]:站点距离场站的步行距离 item[5]:场站的功能 item[6]:场站的面积 item[7]:场站的url item[8]:场站的轮廓 ''' print(item) point_string = item[1] point_arr = str(item[1]).replace(';', '').split(',') point = geojson.Point((float(point_arr[0]), float(point_arr[1]))) properties_point = {'name': str(item[0]), 'way_line': str(item[2])} point_feature = geojson.
说明:SpringBoot支持以下五种方式配置方式,例如将项目的Tomcat端口从8080,更改为9000,可以使用如下方式配置
【方式一】命令行参数 在启动窗口,鼠标右键,选择“Edit Configurations”,在弹出来的窗口中,在Program arguments,里面填“–server.port=9000”,配置格式为两个小横杠(–)开头
这种方式,可以在执行jar包时,附加在执行jar包的命令后面
【方式二】java系统属性 还在刚刚那个窗口中,在Environment,VM options中,填“-Dserver.port=9000”,配置格式为“-D”开头
【方式三】application.properties配置文件 创建application.properties配置文件,在配置文件中写配置,配置以键值对方式书写,格式参考:http://t.csdn.cn/5oiqK
【方式四】application.yml配置文件 创建application.yml配置文件,在配置文件中写配置,配置需要符合yaml文件的格式语法,参考:http://t.csdn.cn/5oiqK
【方式五】application.yaml配置文件 与yml一样,只是文件后缀名不同,就像html、htm,只是后缀名不同,内容格式是相同的
以上五种方式,执行结果都可以修改Tomcat的端口
优先级 以上五种配置的优先级,为命令行方式 > java系统属性方式 > properties > yml > yaml
【方式一】命令行参数方式的优先级最高
总结 虽然SpringBoot项目支持以上五种配置方式,但建议还是选择配置文件的方式,推荐使用application.yml文件
一、简介: 1、DNS的原理: 在Linux系统中,DNS(Domain Name System)是一个重要的网络服务,它负责将域名解析为IP地址以进行网络通信。 Linux DNS是通过域名服务控制器(DNS服务器)实现的,该服务器存储了域名和对应的IP地址,以及其他相关信息。
2、DNS常见的用法和作用: 当Linux系统需要访问某个域名时,它会向DNS服务器发送请求,获取对应的IP地址,然后使用该IP地址进行网络通信。在Linux系统中,常用的DNS服务器软件包括BIND(Berkeley Internet Name Domain)和NSD(Name Server Daemon)。用户可以使用dig命令来测试DNS解析和性能。
二、实验目的: 1、熟悉域名服务器的各种角色 2、学会构建主域名服务器 三、准备: 挂源: 在配置DNS之前要先安装好bind,安装要提前挂源,我们在挂源的时候可用先用
df -h 来看源的挂在路径,然后更改挂源路径
mount /dev/sr0 /XXX/XX 从此可用看出我们已经把源挂在home里面的aa文件中,我们可以再次检测一次挂源路径
df -h 四、安装: 然后我们就可以安装bind服务
yum install bind -y 五、配置: 1、配置准备: 在安装成功后,我们需要先知道我们的ip地址
ifconfig 可以用这个命令来查询我们的ip地址
我们看ens33,ens33` 是 Linux 系统下的一个网络设备标识符。它用于标识系统中的物理或虚拟网卡设备,以便系统能够识别和管理它们。 在 Linux 以及一些基于 Linux 的操作系统(如 CentOS、Ubuntu 等)中,网络设备名称通常由 udev 程序进行动态管理。系统根据硬件设备、驱动程序和网络规则等因素,为每个网络设备分配一个唯一的名称。 作用是让系统可以准确地找到网络设备并为其分配相应的 IP 地址、DNS 信息、路由规则等网络配置。当你连接到网络时,你的系统需要知道使用哪个网卡来发送和接收数据。`ens33` 标识即告诉系统“我是这个网卡”,这样让系统很容易地分配和管理网络配置信息。
所以ens33后面的那个IP是我们的本机ip。
2、配置DNS服务器的全局参数: 然后我们就可以在主配置文件/etc/named.conf中设置DNS服务器的全局参数
vi /etc/named.conf
listen-on port 53 { 127.0.0.1; };
#include<iostream> using namespace std; #include<ctime> int main() { //添加随机数种子,利用当前时间来生成随机数,防止都一样 srand((unsigned int)time(NULL)); //1 系统生成随机数 int num = rand() % 100+1;//rand() 随机生成数字,后面%100,表示范围 0~99 cout << num << endl; //2 玩家进行猜测 int val = 0; while (1) { cout << "请输入你猜的数字:"; cin >> val; if (val > num) { cout << "你猜的数据过大" << endl; } else if (val < num) { cout << "你猜的数据过小" << endl; } else { cout << "你猜对了!" << endl; break; } } system("
什么是Scrcpy https://github.com/Genymobile/scrcpy
Scrcpy是genymobile开源的一款手机镜像软件,通过对手机音视频的采集和同步,可以实现在PC平台上控制手机的功能。
官方解释:此应用程序镜像通过 USB 或 TCP/IP 连接的 Android 设备(视频和音频),并允许使用计算机的键盘和鼠标控制设备。 它不需要任何根访问权限。 它适用于 Linux、Windows 和 macOS。
因为它的易用性,所以广受好评,那么,它又是怎么实现这个易用性的呢?还是得解读一下。
源码分析 Scrcpy是通过app_process的方法,首先将dex或者jar文件push到Android设备中/data/local/tmp中,然后通过adb shell进行调用。一般来讲,访问/data文件夹都需要root权限,而tmp文件夹提供了shell权限就能够访问的方法,因此使用app_process的二进制文件大多数情况下都是放置在/data/local/tmp文件夹下。
这里scrcpy存在一个Feature。当我们运行scrcpy并且投屏成功后,用adb shell到/data/local/tmp文件夹下却无法找到对应的app_process文件,可以尝试着使用
top | grep scrcpy 进行查看,当前scrcpy已经完全加载到内存中并运行的时候,就会将/data/local/tmp文件夹下的二进制运行文件删除掉,不留下一点痕迹。 除此以外,其他的功能应该分为三大块,视频同步,音频同步以及控制同步,接下来我们一块块进行剖析。
1. 视频同步 视频流同步,主要的代码在ScreenEncoder.java里面的streamScreen()方法,通过do while循环的方式实时获取截图并且编码成视频流,具体代码如下:
do { ScreenInfo screenInfo = device.getScreenInfo(); Rect contentRect = screenInfo.getContentRect(); // include the locked video orientation Rect videoRect = screenInfo.getVideoSize().toRect(); format.setInteger(MediaFormat.KEY_WIDTH, videoRect.width()); format.setInteger(MediaFormat.KEY_HEIGHT, videoRect.height()); Surface surface = null; try { mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); surface = mediaCodec.createInputSurface(); // does not include the locked video orientation Rect unlockedVideoRect = screenInfo.
网络安全是一个极具挑战性的领域,涉及到复杂的技术和众多的概念。在这个数字化时代,网络攻击和数据泄露的威胁愈发严重,对于个人和组织来说,保护自己的网络安全至关重要。然而,自学黑客技能并不是一项适合一般人的任务。在这篇文章中,我将分享一些经验,并向大家推荐更合适的学习方法。
坚实的基础知识 首先,黑客技能的学习需要坚实的计算机基础知识。了解计算机网络、操作系统、编程语言和数据结构等基本概念是非常重要的。如果你对这些领域没有基础,自学黑客技能将会是一项极具挑战性的任务。
长期的学习和实践 其次,黑客技能需要长期的学习和实践。网络安全是一个不断演化的领域,新的安全漏洞和攻击技术不断涌现。要想掌握黑客技能,你需要不断跟进最新的技术动态,阅读相关的论文和安全漏洞报告,并进行实际的实验和演练。这需要长期的投入和坚持,一般人很难抽出足够的时间和精力来完成这项任务。
责任心和伦理意识 此外,黑客技能的学习需要高度的责任心和伦理意识。黑客技术可以被用于积极的目的,比如加强网络安全和保护隐私。然而,它也可以被滥用,用于非法的入侵和攻击行为。一个合格的黑客应该具备良好的道德和伦理准则,明确区分合法和非法的行为,并始终将技术用于积极的目的。
考虑到以上因素,我建议对于一般人来说,自学黑客技能可能并不是一个明智的选择。然而,这并不意味着你不能关注网络安全或者提高自己的网络安全意识。下面是一些更合适的学习方法:
参加网络安全培训课程:有许多专门针对网络安全的培训课程和认证项目。参加这些课程可以帮助你系统地学习网络安全知识和技能,并获取相关的证书。阅读网络安全书籍和资源:有很多优秀的网络安全书籍和在线资源可供学习。通过阅读这些书籍,你可以了解到网络安全的基本概念、常见的威胁和防御策略等内容。参加网络安全社区和活动:加入网络安全社区,参加相关的活动和会议,与其他专业人士交流经验和知识。这样你可以从其他人的经验中学习,并建立有价值的人脉关系。遵守网络安全最佳实践:学习并遵守网络安全最佳实践,比如使用强密码、定期更新软件补丁、谨慎点击可疑链接等。这些简单的行为可以有效地提高你的网络安全水平。 总而言之,自学黑客技能并不是适合一般人的任务。学习网络安全需要坚实的基础知识、长期的学习和实践,以及高度的责任心和伦理意识。然而,你仍然可以通过参加培训课程、阅读书籍、参加社区活动和遵守最佳实践来提高自己的网络安全意识和技能。重要的是要明确自己的目标,并选择适合自己的学习方法。
一般要应聘关于测试的工作,面试题会不会很难?下面小编整理了软件测试面试题及答案,欢迎参考!
一、引言
1.1 文档目的
本次文档是为了收集在面试中遇到的一问题与常见的一些答案并不是唯一答案
二、职业规划
2.1 简单的自我介绍下
面试宫,您好,我叫 XXX,来自于 XXXX,目前从事软件测试工作,已经三年工作经验,个人性格,比
较开朗,跟人关系比较好,做事也比较细心三年测试工作经验中,过了不少项目,积累不少项目经验,
前面 1-2 年主要是功能测试,后面这一年主要做接口测试,app 自动化测试能够独立完成软件产品测
试工作,能够独立编写测试文档,包括用例,计划,报告等,熟悉 lnux 跟数据库,熟悉 jmeter 与 python
+ request进行接口测试,也可以使用 pytest框架进行接口自动化测试, python + selenium + pytest
框架进行自动化测试,python + appnium + pytest 移动 app 自动化测试框架,熟悉使用 Jenkins 持
续集成,熟悉 app 专项测试与小程序测试,熟悉抓包工具。
我个人平常喜欢…看书…
我个人觉得测试这一块,主要是对需求了解,需求理解到位,工作当中,一定细心耐心,技术这块,
不断学习能力
如果面试没有说话, 这个是我的一个简单自我介绍,看面试官还有什么需要了解的
2.2 为什么离职
①、尽量谈化敏感答案比如,人际关系不好处理,与上司相处不好、工作压力大等。
人际关系复杂,现代企业讲求团队精神,要求所有成员都能有与别人合作的能力,你对人际关系
的胆怯和避讳,可能会被认为是心理状况不佳,处于忧郁焦躁孤独的心境之中,从而妨碍了你的从业
取向。
收入太低,这样回答会使对方认为你是单纯为了收入取向,很计较个人得失,并且会把“如有更
高的收入,会毫不犹豫地跳槽而去的”这种观念形成对你的思维定势。
分配不公平。现在企业中实行效益薪金、浮动工资制度是很普遍的,旨在用物质刺激手段提高业
绩和效率;同时,很多单位都开始了员工收入保密的措施,如果你在面试时将此作为离开原单位的借
口,则一方面你将失去竟争优势,另一方面你会有爱打探别人收入乃至隐私的嫌疑。
工作压力太大。现代企业生存状况是快节奏的,企业中的各色人等皆处于高强度的工作生存状态
下,有的单位在招聘启事上干脆直言相告,要求应聘者能在压力下完成工作,这是越来越明显的趋向
②、尽量采用与工作能力关系不大、能为人所理解的离职原因。
寻求更大的发展:现有的企业岗位设置难以满足自身职业进一步发展的要求,
换一个更好的平台来挑战自我。
原公司发生了重大客观变化:公司重组或部内部变动,导致工作内容发生重大变化,
无法再继续履行劳动合同,或者直接被裁员等
与公司文化无法融合:每一家企业其实都有自己特有的“文化”,如果你在这家公司里工作,
却无法认可这家公司提倡的一些文化,这就会对企业的发展以及对自己的发展都非常的不利。
所以你想要走出企业的束缚,找到一家跟你更契合的公司工作也是可以的。
使用canvas的必要条件是在HTML标签中定义canvas容器:
<div class="cas"> <canvas id="canvasEle"> sorry, this browser do not support canvas now! </canvas> </div> 因为canvas标签在HTML中是不可用css进行编辑的,所以可以直接让一个div包裹住这个canvas画布。
接下来就是使用js脚本来实现对画布的编辑:
var canvas = document.getElementById("canvasEle"); // 获取canvas画布容器 var ctx = canvas.getContext("2d"); // 获取上下文 // canvas画布的大小不能用canvas.style.width/height来设定 canvas.height = 720; canvas.width = 1276; canvas.style.border = "2px solid pink"; // 这个border是会算进画布宽度中的,会导致canvas.width的实际值比设定值大4px 以上两行代码是必要的,首先获取canvas标签对象,紧接着获取上下文对象ctx,ctx对象中包含了绝大部分绘制canvas上下文的方法。
接下来就是利用ctx对象中的方法对canvas画布进行编辑: // 等边三角形函数 function triangle(left, top, sideLength) { ctx.beginPath(); // 开始路径 ctx.moveTo(left, top); // 设定起点 ctx.lineTo(left - 1/2 * sideLength, 0.87 * sideLength + top); // 设定直线 ctx.
golang使用gorm框架执行原生sql gorm框架执行原生sql有两种方式,作用不同,分别是:
db.exec(“sql语句”) //执行插入删除等操作使用
db.raw(“sql语句”) //执行查询操作时使用
gorm中exec和raw方法的区别大致可以说是raw用来查询,执行其他操作用exec,因为本人也不是非常清楚,所以只好这么说。
20230612更新,上面的说法有问题,引用Stack Overflow的网友说的
(*gorm.DB).Exec does not return an error, if you want to see if your query failed or not read up on error handling with gorm. Use Exec when you don’t care about output, use Raw when you do care about the output.
大致意思是:(*gorm.DB).Exec不会返回错误。如果不关心输出,请使用Exec;如果关心输出,则使用Raw。
具体操作请看官方文档,附GORM执行Exec和Raw的官方文档
https://gorm.io/docs/sql_builder.html
项目场景: 树莓盘Linux系统下 更新软件源遇到的问题:
E: 无法获得锁 /var/lib/apt/lists/lock。锁正由进程 1055(packagekitd)持有
N: 请注意,直接移除锁文件不一定是合适的解决方案,且可能损坏您的系统。
E: 无法对目录 /var/lib/apt/lists/ 加锁
问题描述 E: 无法获得锁 /var/lib/apt/lists/lock。锁正由进程 1055(packagekitd)持有 N: 请注意,直接移除锁文件不一定是合适的解决方案,且可能损坏您的系统。 E: 无法对目录 /var/lib/apt/lists/ 加锁 解决方案: sudo rm /var/cache/apt/archives/lock sudo rm /var/lib/dpkg/lock sudo apt-get update 完美解决:
LRU 介绍 https://zhuanlan.zhihu.com/p/52196637
class LRUCache { constructor(capacity) { this.capacity = capacity; this.cache = new Map(); } get(key) { if (!this.cache.has(key)) { return -1; } const value = this.cache.get(key); this.cache.delete(key); this.cache.set(key, value); return value; } put(key, value) { if (this.cache.has(key)) { this.cache.delete(key); } else if (this.cache.size >= this.capacity) { const leastUsedKey = this.cache.keys().next().value; this.cache.delete(leastUsedKey); } this.cache.set(key, value); } } 在构造函数中,我们传入了一个容量参数capacity,并创建了一个名为cache的空Map对象。在get()方法中,我们首先判断cache中是否存在该key,如果不存在则返回-1。如果存在,则将该key对应的值取出,并从cache中删除该key,再重新将该key和其对应的值添加到Map中,以保证其在Map中处于最近使用状态。最后,返回该key对应的值。
在put()方法中,我们首先判断cache中是否存在该key,如果是,则删除该key。如果cache已满,则查找cache中最久未使用的key并删除它。然后,将新的(key, value)添加到cache中。
需要注意的是,在上述代码中,我们使用了ES6中的Map数据结构来存储缓存数据,因为它具有按照插入顺序排序的特性,这样可以避免手动维护一个额外的链表来记录缓存数据的访问时间戳等信息。
基于哈希链表的LRU javascript //定义哈希链表节点类 class HashNode { constructor(key, value) { this.
效果图 一、导入依赖 implementation 'com.yanzhenjie:permission:1.1.2' 同步后出现一下报错
这是因为混合支持库。通过添加android.enableJetifier=true选择androidX作为您的支持库 , 如下图:再次同步即可成功
二、添加权限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.CAMERA" /> 三、请求授权 //获取权限 private void getPurView() { AndPermission.with(MainActivity.this) .requestCode(REQUEST_CODE_PERMISSION) .permission(Permission.CAMERA,Permission.STORAGE) .callback(permissionListener) // rationale作用是:用户拒绝一次权限,再次申请时先征求用户同意,再打开授权对话框; // 这样避免用户勾选不再提示,导致以后无法申请权限。 // 你也可以不设置。 .rationale(new RationaleListener() { @Override public void showRequestPermissionRationale(int requestCode, Rationale rationale) { // 这里的对话框可以自定义,只要调用rationale.resume()就可以继续申请。 AndPermission.rationaleDialog(MainActivity.this, rationale).show(); } }) .start(); } /** * 回调监听。 */ private PermissionListener permissionListener = new PermissionListener() { @Override public void onSucceed(int requestCode, @NonNull List<String> grantPermissions) { switch (requestCode) { case REQUEST_CODE_PERMISSION: { //权限设置成功 if (AndPermission.
文件大小过大的时候可以对文件进行分片上传
相当于如果10M的文件,可以把每个文件分成1M的大小上传,然后上传完后再进行合并
file.vue
<template> <input type="file" id="fileBtn" /> <input type="button" value="上传" @click="upload" /> {{ btnFile }} </template> <script lang="ts" setup> import { simpleUpload, sliceUpload, merge } from '@/services/upload'; const chunkSize = 3; const multipleSize = 1; // 上传 const upload = (/* index = 0 */) => { console.log('upload'); const btnFile: any = document.querySelector('#fileBtn'); const file = btnFile?.files[0]; isMutiple(file); }; // 是否需要分片 const isMutiple = async (file: any, index = 0) => { const { name, size } = file; const M = Math.
针对(旧版)51单片机 1,晶振振荡频率(fosc)
fosc即板子所使用的晶振频率,如常用的11.0592Mhz。
2,时钟周期
时钟周期 = 1 / fosc ,单位为us。
3,机器周期
机器周期 = 12 / fosc ,单位为us。
为啥是12?
因为绝大多数51单片机默认12分频,分频原理直接看第四点。
12分频的原因:老版51单片机使用复杂操作集,导致1个时钟周期内CPU根本无法完成一条指令,因此默认需要12个时钟周期。
有这么一个公式:机器周期 = 12 * 时钟周期
这个公式只针对老版12分频51单片机,不是数学真理那种存在!!!
12倍这个关系归根结底是晶振频率进行了12分频
在stm32中压根没有机器周期这个概念,机器周期就是时钟周期,因为stm32够快
针对51、stm32单片机 4,分频的原理与作用(51、32通用)
原理:分频其实就是将fosc倍除。
作用:分频的作用是增长时钟周期(还有控制功耗的作用,时钟频率越快功耗越高,这里就不讲了)
以下有两种理解方式:例如72Mhz晶振(fosc),7200分频系数
一,时钟周期 = 分频系数 / fosc(推荐)
100 (us) = 7200 / 72
二,先倍除fosc,后转换为时钟周期
72 / 7200 = 0.01MHz
100 (us) = 1 / 0.01
若不分频时,时钟周期 = 1/72 = 0.01388888888 us,可以发现不分频时时钟周期极短。
自己可以扩大或缩小上面的分频系数,再次带入公式,就可以发现分频的作用是增长时钟周期。
5,扩大时钟周期的作用
我们知道单片机中最大的定时器也就16位,最多计数次数为65535+1(溢出)=65536次,每次计数的时间间隔就是时钟周期。
若机器周期为定时器最小分辨率 1/72us,则最大的定时器一共可以定时 910us。
而这样的最大溢出时间有时并不满足实际需要,因此需要扩大机器周期来延长定时器的溢出时间,此时便通过设置分频系数来解决(仅stm32可以设置,在启动文件 SystemInit 函数中)。
在实际vue项目开发中,有时el-upload上传框的默认长度和宽度不是自己想要的,这就需要自行修改,方法也简单,先上效果对比图:
默认的上传框尺寸 若要修改尺寸,则添加如下代码即可:
<template> <div id="upload"> <el-upload drag multiple> <i class="el-icon-upload"></i> <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div> <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过1Mb</div> </el-upload> </div> </template> <script></script> <style scoped> .el-icon-upload:before { content: '\e7c3' //设置图标 } .el-icon-upload { font-size: 30px; //图标的尺寸大小 margin: 4px 0 2px; //图标与四周元素的间距 } //下面这几行代码就是设置上传框的长宽,可以按百分比来设置也可以用px去设置 /deep/ .el-upload .el-upload-dragger { width: 120%; height: 80%; } </style> 上面的样式代码中scoped是必要的,缺少可能会导致显示不出预期的效果,下面来看修改后的效果图:
调整后的上传框尺寸
一、安装 1、apt安装(只能安装默认版本) sudo apt-get install libeigen3-dev 其安装路经位于
/usr/include/eigen3 2、源码安装(可以安装所有的历史版本) git clone https://gitlab.com/libeigen/eigen.git cd eigen git checkout -p 3.3.4 //输入需要安装的版本 mkdir build cd build cmake… sudo make install 二、查看版本 安装成功后,可以查看版本
pkg-config --modversion eigen3 >>> xxx@xxx-UPX-TGL01:~$ pkg-config --modversion eigen3 3.3.7
1、二叉树 二叉树(Binary Tree)是一种特殊的树形结构。它的度数为2,即二叉树的每个结点最多有两个子结点。每个子结点分别称为左孩子、右孩子,它的两棵子树分别称为左子树、右子树。
2、平衡二叉树 每次插入数据都会旋转,相对平衡
二叉树与平衡树的区别:二叉树每次插入不需要变动已有的节点、平衡树需要旋转节点得到平衡
3、红黑树 是一种自平衡的二叉查找树。
从红黑树的任一节点到其每个叶子节点的所有路径都包含相同数目的黑色节点。
总体来说,在插入或者删除节点时,红黑树旋转的次数比平衡二叉树少,因此在插入与删除操作比较频繁的情况下,选用红黑树。
推荐一个模拟网址:
https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
目录
1、前言
2、标记-清除算法
3、标记-整理算法
4、标记-复制算法
5、总结
1、前言 说起垃圾回收(Garbage Collection)(本文简称GC)。相信同时对C++和Java有了解的小伙伴都知道,C++在new完对象后,是需要手动delete对象来释放内存的,而Java则不需要。虽然我们Java程序员不需要去手动的释放内存,但是了解JVM如何处理这一过程对我们来说也是很有必要的。
JVM对于垃圾回收这一篇幅其实是很长的,既然要对垃圾进行回收,那么不可避免的要思考三个问题:①哪些需要回收、②什么时候回收、③如何回收。
本文主要先讲解三个经典的垃圾回收算法,后面笔者会陆续更新其他的内容(比如什么是安全点,什么是安全区,经典垃圾回收器等)。
2、标记-清除算法 如上图所示,标记-清除算法就是每次进行垃圾回收时,标记出可以回收的对象,然后直接将这些对象回收(即释放对应区域的内存)即可。
标记-清除算法优点显而易见:那就是简单、高效(对于清除这一步骤来说)。因为我们只需要将标记出的对象直接清除便可,因此效率很高。
但是缺点相信学过操作系统的小伙伴肯定一眼就看出来了:久而久之会存在大量内存碎片,导致大对象无法分配到所需的内存空间。
3、标记-整理算法 如上图所示,标记-整理算法就是每次进行垃圾回收时,标记出可以回收的对象,然后将这些对象回收后,将存活的对象整理到连续的内存空间去。 标记-整理算法实际上就是标记-清除算法的“改进版”,我们上述说到标记-清除算法的缺点就是会存在大量内存碎片,导致大对象无法分配到所需的内存空间。标记-整理算法在标记-清除算法的基础上,加了一个将存活对象移动到连续的内存空间这一步骤。
标记-整理算法的优点肯定大家也想到了——内存利用的更加充分,不会存在内存碎片,导致大对象分配不到所需的内存空间。
但是缺点想必大家也看出来了——回收时,每次都要将对象移动到一起,性能肯定会受到一定的影响。特别是当大部分对象都要回收时,只有少部分离散的对象存活,这个时候性能被影响的会更加明显。
4、标记-复制算法 如上图所示,标记-复制算法就是将内存区域分为两部分(这里我们称为回收区和保留区),垃圾回收时,我们每次标记出需要回收的对象,然后将不需要回收的对象复制到“保留区”后,将存活区的所有对象一起清除(因为我们在保留区保留了不需要回收的对象,所以回收区都可以回收了)。然后原回收区就空了,变成保留区,原保留区有对象,此时变成回收区。
标记-复制算法相对上述标记-整理算法来说,对于大部分对象都要回收时,只有少部分离散的对象存活这个场景来说,更加适用、高效,解决了这个场景下标记-整理算法的不足。
缺点也很明显,那就是我们每次都有一部分内存区域用不上(因为要拿一部分来当保留区)。
5、总结 本文只是比较快速的介绍了一下三个经典的垃圾回收算法,同时也说明了他们的优缺点。这里我们给大家一些总结:
对于追求垃圾回收延迟低(即垃圾回收这一过程快)的场景下,推荐使用“标记-清除算法”。对于大部分对象都要回收时,只有少部分离散的对象存活这个场景下,我们推荐使用“标记-复制算法”。(在后面我们讲到分代思想时,新生代大部分都需要回收,因此是使用这个算法。)对于少部分对象要回收,大部分对象都存活的场景下,我们推荐使用“标记-整理算法”(在后面我们讲到分代思想时,老年代大部分都不需要回收,因此是使用这个算法。)
一、原子类简介 1 什么是原子类 Java中提供了一些原子类,原子类包装了一个变量,并且提供了一系列对变量进行原子性操作的方法。原子性的意思是对于一组操作,要么全部执行成功,要么全部执行失败,不能只有其中某几个执行成功。在多线程的情况下能够保证操作 不会被中断,从而能保证并发安全
2. 与锁的区别 原子类作用和锁挺像,都可以保证并发情况下的线程安全。但是原子类比锁更具有优势:
粒度更细:
原子变量可以把多线程竞争范围缩小到变量级别,这是我们可以获得的最细粒度的情况,通常锁的粒度都要比原子变量的粒度大
效率更高:
通常,使用原子类的效率会比使用锁的效率更高,除了高度竞争的情况
3. 原子类的底层实现 目前Java中提供的原子类大部分底层使用了CAS锁(CompareAndSet自旋锁),如AtomicInteger、AtomicLong等;也有使用了分段锁+CAS锁的原子类,如LongAdder等。
4. 原子类种类 在JDK中J.U.C包下提供了种类丰富的原子类,以下所示:
类型具体类型Atomic* 基本类型原子类AtomicInteger、AtomicLong、AtomicBooleanAtomic*Array 数组类型原子类AtomicIntegerArray、AtomicLongArray、AtomicReferenceArrayAtomic*Reference 引用类型原子类AtomicReference、AtomicStampedReference、AtomicMarkableReferenceAtomic*FieldUpdater 升级类型原子类AtomicIntegerfieldupdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdaterAdder 累加器LongAdder、DoubleAdderAccumulator 积累器LongAccumulator、DoubleAccumulator 二、原子类使用案例 1. Atomic* 基本类型原子类 这里以 AtomicInteger 为例,下面是 AtomicInteger常用方法 ,其他的两种AtomicLong、AtomicBoolean和它相似:
方法作用public final int get()获取当前的值public final int getAndSet(int newValue)获取当前的值,并设置新的值public final int getAndIncrement()获取当前的值,并自增+1public final int getAndDecrement()获取当前的值,并自减-1public final int getAndAdd(int delta)获取当前的值,并加上预期的值。getAndIncrement和getAndDecrement不满足,可使用当前方法boolean compareAndSet(int expect, int update)如果输入的数值等于预期值,则以原子方式将该值更新为输入值(update) 代码演示:
/** * 演示AtomicInteger的基本用法,并对比非原子类的线程安全问题 */ public class AtomicIntegerDemo1 implements Runnable { private static final AtomicInteger atomicInteger = new AtomicInteger(); private static final AtomicInteger atomicInteger2 = new AtomicInteger(); //原子类型自增 public void atomicIncrement(){ atomicInteger.
mysql数据库 一、数据库的基本概念二、关系数据库三、SQL语句增改查删 四、natvicat for mysql软件 一、数据库的基本概念 数据(data)
描述事物的符号记录包括数字、文字、图形、图像、声音、档案记录等以“记录”形式按统一的格式进行存储 表:
将不同的记录组织在一起用来存储具体数据 数据库:
表的集合,是存储数据的仓库以一定的组织方式存储的相互有关的的数据库是按照数据结构来组织、存储和管理数据的仓库
数据库的管理系统:
是实现对数据库资源有效组织、管理和存取的系统软件。
拥有数据库的建立和维护功能、数据库定义功能、数据库操纵功能、数据库的运行管理功能、通信功能
数据库系统:
是一个人机系统,由硬件、OS、数据库、DBMS、应用软件和数据库用户组成用户可以通过DBMS或应用程序操作数据库
二、关系数据库 关系数据库系统是基于关系模型的数据库系统
关系模型的数据结构使用简单易懂的二维数据表
关系模型可用简单的“实体-关系”(E-R)图来表示
E-R图中包含了实体(数据对象)、关系和属性三个要素
二维表格:
每一行称为一条记录,用来描述一个对象的信息
每一列称为一个字段,用来描述对象的一个属性
非关系数据库:
关系数据库为SQL,非关系数据库为noSQL(not only sql)
存储数据不以关系模型为依据,不需要固定的表格式
非关系型数据的优点:
数据库可高并发读写对海量数据高数据存储与访问数据库具有高扩展与高可用性
常用的非关系数据库:redis、mongoDB等 三、SQL语句 常用的数据类型:
int:整形 无符号[0,2^32-1],有符号[-2^31,2^31-1] float:单精度浮点 4字节32位 double:双精度浮点 8字节64位 char:固定长度的字符类型 varchar:可变长度的字符类型 text:文本 image:图片 decimal(5,2):5个有效长度数字,小数点后面有2位 操作:
增 增加数据库命令:
create database 数据库名;
use + 数据库名 能切换到指定数据库
增加表命令:
create table 表名 (字段1 数据类型,字段2 数据类型。。。。。。,primary key 主键名);
主键一般选择能代表唯一性的字段不允许取空值(null),一个表只能由一个主键。
增加表的内容:
insert into 表名
eclipse使用Java编写简易版个人所得税计算器
文章目录 前言代码实现 前言 计算个人所得税的缴纳情况。用户从控制台输入税前工资额金额,系统根据用户输入的工作金额计算应缴纳的税额
工资个税的计算公式为:
应纳税额 = (工资薪资所得 - 扣除数)* 适用税率 - 速算扣除数
全月应纳税所得额 = 月工资薪资所得 - 扣除数
2011年9月1日起执行7级超额累进税率:扣除数为3500元
代码实现 具体代码如下:
package day03; import java.util.Scanner; public class IncomeTax { public static void main(String[] args) { Scanner scan = new Scanner(System.in); System.out.println("请输入税前工资金额(¥):"); double total = scan.nextDouble(); if(total < 3500) { System.out.println("您不需要缴纳个人所得税!"); }else if((total - 3500) <= 4500) { double tax = (total - 3500) * 3/100; System.out.println("您应缴纳:"+tax+"元个人所得税"); }else if((total - 3500) <= 4500) { double tax = (total - 3500) * 10/100 - 105; System.
数据库各种连接方式的on、and、where条件使用
文章目录 前言使用on条件,A为主表使用on条件,B为主表使用on、and主表条件使用on、where主表条件使用on、and条件,a.type<>1使用on、where条件,a.type<>1使用on、and从表条件使用on、where从表条件使用on、and从表条件,从表Bcard<>1111使用on、where条件,从表Bcard<>1111inner内链接,使用on、and条件inner内连接,使用on、where条件 前言 内连接:只保留满足on条件的数据,剔除不匹配的数据
左外连接:无论on中的条件满不满足,都保留左表所有数据
右外连接:无论on中条件满不满足,都保留右表的所有数据
全外连接:无论on中条件满不满足,都保留所有表的所有数据
表A
表B
使用on条件,A为主表 select a.*,b.* from a left join b on a.id=b.id; 注:关联多条,从表有重复数据,一般不去重,显示出A表全部数据,005关联两次
结果如下:
使用on条件,B为主表 select a.*,b.* from b left join a on a.id=b.id; 注:显示出B表全部数据
结果如下:
使用on、and主表条件 select a.*,b.* from a left join b on a.id=b.id and a.type=1; 注:以左表全匹配进行连接,之后用and筛选,不符合and条件的数据左表保留,右表为null,B表只显示001、002的数据
结果如下:
使用on、where主表条件 select a.*,b.* from a left join b on a.id=b.id where a.type=1; 注:先走on条件,在过滤出type=1的数据,on关联时用,where结果集过滤时用
结果如下:
使用on、and条件,a.type<>1 select a.*,b.* from a left join b on a.
文章目录 Java语言基础一、方法的重写(Override)二、重写和重载的区别三、访问控制3.1、package3.2、import3.3、public3.4、private3.5、protected3.6、默认访问控制符3.7、访问控制修饰符对比 四、static:静态的4.1、静态变量4.2、静态方法4.3、静态块4.4、成员变量和静态变量的区别 五、final:不能变5.1、修饰成员变量5.2、修饰方法5.3、修饰类 Java语言基础 包括方法的重写(Override)、重写和重载的区别、访问控制(package、import、public、private、protected、默认访问控制符、访问控制修饰符对比)、静态变量、静态方法、静态块、成员变量和静态变量的区别、修饰成员变量、修饰方法、修饰类。
一、方法的重写(Override) 1)子类可以重写(覆盖)继承来自父类的方法,即方法名和参数列表与父类的方法相同,但实现方式不同
2)当子类对象的重写方法被调用时,无论是通过子类的引用调用还是通过父类的引用调用,运行的都是子类重写后的方法
public class Ooo { public static void main(String[] args) { Aoo o1 = new Boo(); Boo o2 = new Boo(); o1.show(); //结果为Java! o2.show(); //结果为Java! } } class Boo extends Aoo{ void show() { System.out.println("Java!"); } } class Aoo{ void show() { System.out.println("Python!"); } } 3)在子类重写的方法中,可以通过super关键字调用父类的“原始”方法
public class Ooo { public static void main(String[] args) { Aoo o1 = new Boo(); o1.
首先介绍一下VPP在C#里常用的三个控件:
1.图像显示控件(CogRecordDisplay):
CogRecordDisplay1.InteractiveGraphics.Clear();
CogRecordDisplay1.Record = toolBlock.CreateLastRunRecord().SubRecords[0];
CogRecordDisplay1.Fit();
2.Vpp文件编辑控件(CogToolBlockEditV2):
var CogToolBlockEditV21 = new CogToolBlockEditV2();
CogToolBlockEditV21.Dock = DockStyle.Fill;
this.Controls.Add(CogToolBlockEditV21);
this.CogToolBlockEditV21.Subject =(CogToolBlock)CogSerializer.LoadObjectFromFile(ToolBlockPath);
3.相机工具编辑控件(CogAcqFifoEditV2):
var CogAcqFifoEditV2=new CogAcqFifoEditV21();
var cogToolBlock = (CogToolBlock)CogSerializer.LoadObjectFromFile(acqFifoFilePath);
this.CogAcqFifoEditV21.Subject = (CogAcqFifoTool)cogToolBlock1.Tools[“CogAcqFifoTool1”];
第1步:在容器工具CogTooblock制作VPP,并保存本地
第2步 : 新建C#工程,选择 .NETFramework4.7 或以上版本
第3步:添加下述VisionPro控件
※ 如果找不到VisionPro控件,尝试运行下述文件C:\Program Files (x86)\Cognex\VisionPro\bin\CreateVProTab.exe"
第4步:保存工程,将VPP拷贝至Debug文件夹下
第5步 :添加VisionPro的dll引用
第6步 :导入命名空间,声明变量
第7步 :Form1_Load和Closing中添加代码,载入VPP和关闭VPP
第8步:获取工具句柄
第9步:控制运行过程
第10步:执行逻辑和视觉算法
第11步 : 绑定控件,执行检测,输出结果并显示
第12步 :输出图像和结果
文章目录 python学习0.安装pytorch1.验证pytorch已经安装成功1.1确定pytorch版本1.2.测试pytorch基础功能1.3.在GPU上测试pytorch1.4使用实例代码测试 python学习 python学习
0.安装pytorch 官方安装pytorch地址
1.验证pytorch已经安装成功 1.1确定pytorch版本 import torch print(torch.__version__) 如果没有报错,同时输出了正确版本号,就说明PyTorch已经成功安装了。
1.2.测试pytorch基础功能 为了确保PyTorch基础功能正常工作,可以进行以下测试:
1.测试是否可以创建张量:
import torch x = torch.Tensor(5, 3) print(x) 如果没有报错,同时输出了5行3列的张量,就说明可以创建张量。
2.测试是否可以进行张量计算
import torch x = torch.Tensor(5, 3) y = torch.Tensor(3, 4) z = torch.mm(x, y) print(z) 如果没有报错,同时输出了5行4列的张量,就说明可以进行张量计算。
1.3.在GPU上测试pytorch 如果电脑有GPU支持,建议在GPU上测试PyTorch是否正常工作。测试代码如下:
import torch if torch.cuda.is_available(): x = torch.Tensor(5, 3).cuda() y = torch.Tensor(3, 4).cuda() z = torch.mm(x, y) print(z) 如果没有报错,同时输出了5行4列的张量,就说明PyTorch GPU版本也正常工作。
1.4使用实例代码测试 为了更加确认PyTorch是否正常工作,可以使用PyTorch官方提供的示例代码进行测试,例如以下代码:
import torch import torchvision model = torchvision.
Mnocle3往期精彩内容,因为monocle2有问题,且官网也放弃了monocle2,目前用的比较主流的拟时方法就是monocle3了。Mnocle3我们也写过全面的内容,不论是基础的分析还是个性化分析:
Monocle3(1):单细胞拟时分析---分析(详细注释版)
Monocle3(2):单细胞拟时分析可视化---普通版
Monocle3:单细胞拟时分析---个性化分析思路及可视化
Mnocle2有一个功能就是可以做拟时热图,在monocle3个性化分析中我们也提供过一种方式,只不过将拟时进行了区间化:
image.png
但是很多小伙伴钟情于Mnocle2的那种形式的热图,一致再问monocle3可以不可做那种图,这里我们也提供做法,是可以实现monocle2拟时热图的效果的,而且我们增添了内容,对拟时进行分块,并作一下GO富集分析,最后使用AI将两者结合,就是一幅完美的展示图。
image.png
Monocle2个性化分析内容我们做过基因随拟时变化的趋势分析及可视化(单细胞拟时分析:基因及通路随拟时表达变化趋势)。这里,我们也在monocle3中实现此内容:[图片上传失败...(image-dd1adc-1686641408024)] 当然了,还是那句话,我们的帖子绝不是单纯的做一个monocle3热图,在这个帖子中有原创函数,构建函数的思路也写在了里面,对于初学者需要拔高的小伙伴,应该是有帮助的!接下来,我们看看具体的内容:
本贴的分析作图内容都是基于monocle3分析构建好cds和做完ordercell之后!
文章目录 一、介绍1.1 示例问题1.2 邻域搜索 二、大邻域搜索三、自适应大邻域搜索3.1 设计ALNS算法3.2 ALNS框架的属性3.3 与其他元启发式算法的关系3.4 并行 四、LNS和ALNS的应用4.1 车辆路径应用4.2 其他应用 五、超大规模邻域搜索5.1 可变深度方法5.2 基于网络流量的改进算法5.2.1 由循环定义的邻域5.2.2 由路径定义的邻域5.2.3 由赋值和匹配定义的邻域 5.3 其他VLSN算法 六、结论七、案例讲解&代码实战 一、介绍 在过去的15年中,基于大邻域搜索(LNS)和变异自适应大邻域搜索(ALNS)的启发式算法已经成为解决各种运输和调度问题的一些最成功的范例。
大邻域搜索方法通过使用试探法来探索复杂的邻域(交替地破坏和修复解来逐渐改进初始解)。
使用大邻域使得在每次迭代中找到更好的候选解成为可能,并因此遵循更有希望的搜索路径。
本博客从大邻域搜索的一般框架出发,深入研究了自适应大邻域搜索,讨论了该框架的设计思想和性质。讨论了大邻域搜索方法在路由和调度中的应用。我们在本章结束时介绍了超大规模邻域搜索(VLSN)的相关框架,并讨论了与LNS的相似之处,然后得出了一些关于利用大邻域的算法的结论。
然而,搜索大的邻域是耗时的,因此使用各种过滤技术来限制搜索。在VLSN算法中,邻域通常被限制为能够被有效搜索的解的子集。在LNS中,邻域由用于破坏和修复现有解决方案的方法(通常是启发式方法)隐式定义。
两个相似的术语LNS和VLSN可能会引起混淆。我们一贯使用VLSN算法来搜索非常大的邻域和LNS,以获得基于破坏和修复邻域的特定元启发式算法
1.1 示例问题 在这一章中,我们将提到两个示例问题:旅行商问题(TSP)和一个一般化的有容量限制的车辆路径问题(CVRP)。
TSP和CVRP的解的例子如图4.1所示。
1.2 邻域搜索 在本节中,我们正式引入术语:邻域搜索。
我们假设组合优化问题是一个极小化问题,假设 X X X 是该问题的所有可行解集合, c ( x ) c(x) c(x) 为该问题的目标函数。
定义一个解 x ∈ X x \in X x∈X 的邻域为 N ( x ) N(x) N(x),如果 c ( x ) ≤ c ( x ′ ) , ∀ x ′ ∈ N ( x ) c(x) \le c(x'),\forall x' \in N(x) c(x)≤c(x′),∀x′∈N(x),则称解 x x x 是一个局部最优解。
01、Selenium 操作被屏蔽 使用selenium自动化网页时,有一定的概率会被目标网站识别,一旦被检测到,目标网站会拦截该客户端做出的网页操作。
比如淘宝和大众点评的登录页,当手工打开浏览器,输入用户名和密码时,是能正常进入首页的,但是如果是通过selenium打开, 会直接提示验证失败,点击框体重试。
本文介绍一种办法,不需要修改浏览器属性,不需要注入JavaScript脚本,也能轻松绕过网站检测。
02、Selenium为何会被检测 每一个浏览器访问网站时,都会带上特定的指纹特征,网站会解析这些特征,从而判断这次访问是不是自动化程序。
一个最广为人知的特征是window.navigator.webdriver,该特征直接标明此浏览器是webdriver程序。当一个浏览器通过selenium启动后,在开发者工具中输入这个属性,会发现被标为 true, 而手工打开的浏览器是 false。
实际上,浏览器被检测为webdriver程序的特征并不止这一个,这意味着,就算你通过修改属性,也不一定能绕过网站的检测。
我们可以通过 sannysoft 来检测浏览器指纹,如果浏览器是通过selenium等自动化程序打开的,访问这个网址后会有很多特征暴露这些指纹,这些特征的值和手工打开后的值是不一样的,因此可以很轻易被别人检测出来。
有人也试图不用selenium,换成puppeter和playwright这样的自动化工具,但是结局都是一样的。
03、Selenium避免被检测方法 浏览器在启动时就会带上指纹特征,如果使用自动化程序启动时已经被标记,那为什么不直接用手工启动,然后用Selenium连接已经启动的浏览器呢?那手工打开浏览器要做什么操作才能让Selenium连接呢?Selenium又是怎样连接手工打开的浏览器呢?
我在 Selenium连接已存在的浏览器1 这篇文章详细记录了需要的步骤,概括起来:
1、打开浏览器时添加以下参数:
--remote-debugging-port=9222 --user-data-dir="C:\selenium\ChromeProfile" 2、selenium中设置浏览器选项,通过上面设置的 9222端口连接浏览器:
from selenium.webdriver.chrome.options import Options chrome_options = Options() chrome_options.add_experimental_option("debuggerAddress", "127.0.0.1:9222") driver = webdriver.Chrome(options=chrome_options) 通过 subprocess 运行浏览器
当然,做自动化程序一般不会手工点击图标来打开浏览器,我们可以用命令行启动浏览器,然后再用 selenium 连接。
如果文章对你有帮助,记得点赞,收藏,加关注。会不定期分享一些干货哦...... END配套学习资源分享 最后: 为了回馈铁杆粉丝们,我给大家整理了完整的软件测试视频学习教程,朋友们如果需要可以自行免费领取 【保证100%免费】
软件测试面试文档
我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
全套资料获取方式:
1.信息化与信息系统 1.1 信息安全的特性 保密性:信息不被泄露给未授权的个人、实体和过程不被其使用的特性;
完整性:保护资产的正确和完整的特性,就是确保接收到的数据就是发送的数据
可用性:需要时,授权实体可以访问和使用的特性;
不可抵赖性:指建立有效的责任机制,防止用户否认其行为。比如在电子商务中,采用数字签名
1.2组织过程资产和事业环境因素的区别 1.3 过程域分组 量化靠性能定量,优化靠改革因果。定义靠技术组织决策,可管靠管控计配分析
量化找性能、定量;
优化找改革、因果;
定义找集训、确焦验、策技义、风发;
可管找需求管理和其他
过程组织非环境,项目团管非需求,工程技术靠研发,支持过程靠其他
1.4 法律法规 投标保证2,
备案质疑7,
履约添购10,
通知修改保存投诉15,
招标20,
中标30
两个以上单位 == 1
投标人 >= 3
投标文件截止日期 - 修改通知 >= 15
投标文件截止日期 - 招标文件发出 >= 20
开标日期 == 投标文件截止日期
ZJJ >= 5 && ZJJ % 2 == 1 && JJ / ZJJ >= 2/3
签合同 - 中标通知 <= 30
添购金额 / 原采购金额 <= 10%
合格供应商 >= 3
可以通过以下步骤在Mac上卸载Node:
打开终端应用程序。运行以下命令以卸载Node: sudo rm -rf /usr/local/{bin/{node,npm},lib/node_modules/npm,lib/node,share/man/*/node.*} 这将删除Node及其相关组件。
3. 输入管理员密码以确认操作。
4. 运行以下命令以验证Node是否已成功卸载: node -v 如果您看到“command not found”或类似的消息,则说明Node已成功卸载。
请注意,这将删除Node及其相关组件,包括npm和任何全局安装的包。如果您只想卸载Node而保留npm和全局包,请删除上述命令中的“npm”部分。
一、FFmpeg简介。
二、FFmpeg常用参数及命令。
三、FFmpeg在Unity 3D中的使用。
1、FFmpeg 录屏。
2、FFmpeg 推流。
3、FFmpeg 其他功能简述。
一、FFmpeg简介 对于FFmpeg,其官网上是这样介绍的:
FFmpeg is the leading multimedia framework, able to decode, encode, transcode, mux, demux, stream, filter and play pretty much anything that humans and machines have created.
FFmpeg能够实现对视频音频编码、解码、转码、流传输等等一系列功能。它包含有libavcodec, libavutil, libavformat, libavfilter, libavdevice, libswscale,libswresample 库。其中:
libavcodec 是一个包含用于音频/视频编解码器的解码器和编码器的库。
libavutil 是一个包含简化编程功能的库,包括随机数生成器,数据结构,数学例程,核心多媒体实用程序等等。
libavformat 是一个包含多媒体容器格式的解复用器和复用器的库。
libavdevice 是一个包含输入和输出设备的库,用于从许多常见的多媒体输入/输出软件框架中获取和呈现,包括Video4Linux,Video4Linux2,VfW和ALSA。
libavfilter 是一个包含媒体过滤器的库。
libswscale 是一个执行高度优化的图像缩放和色彩空间/像素格式转换操作的库。
libswresample 是一个执行高度优化的音频重采样,重新矩阵化和样本格式转换操作的库。
二、FFmpeg常用参数及命令 1、命令的格式: ffmpeg [global_options] {[input_file_options] -i input_url} ... {[output_file_options] output_url} .
一、printf()输出函数 printf() 函数是 C/C++ 语言中用于输出格式化字符串的函数。
封装于头文件:#include <stdio.h>
格式:int printf(const char *format, ...);
int:表示输入的个数;
print:输出函数;
const:存储类型;
char:数据类型;
format:是一个字符串,表示要输出的格式化信息;
. . . :表示可变参数列表,可以包含多个变量,这些变量将按照format中的格式被输出;
printf() 函数返回一个整数,表示成功输出的字符数,不包括换行符。如果输出过程中发生错误,例如无法匹配指定的格式或读取了不合法的数据,则会返回负数。
使用格式:printf("格式控制串",参数列表)
注意:()不能省略,逗号必须存在。
用例(eg)如下:使用 printf() 函数输出了不同类型的数据。
二、scanf()输入函数 scanf() 函数是 C/C++ 语言中用于从标准输入设备(键盘)读取数据的函数。
封装于头文件:#include <stdio.h>
格式:int scanf(const char *format, ...);
int:表示输入的个数;
scanf:输入函数;
const:存储类型;
char:数据类型;
format:是一个字符串,表示要读取的数据的格式;
. . . :表示可变参数列表,可以包含多个变量,这些变量将按照format中的格式被读取;
scanf() 函数返回一个整数,表示成功读取的变量个数。如果读取过程中发生错误,例如无法匹配指定的格式或读取了不合法的数据,则会返回负数。
使用格式:scanf("格式控制串",地址列表)
注意:()不能省略,逗号必须存在;
元素之间可以使用空格、tab\回车表示元素输入的结束;
回车表示scanf输入的整体结束;
需要加空格两个情况 :多次输入单字符,格式串不单单只有格式控制符,scanf("b=%d",&b);
吸收垃圾字符:空格 抑制字符%*c;
用例(eg)如下:
1.输入一个值,并且格式控制串只有格式控制符。 2.输入一个值,格式控制串有多余的字符。 3.连续输入多个,格式控制串只有格式控制符。 4.单字符多次输入(重点)。 错误示范:b打印了回车键。
正确示范:在如下位置使用吸收垃圾字符:空格 或者 抑制字符%*c。
三、getchar()函数 getchar() 函数是 C/C++ 语言中用于从标准输入设备(键盘)读取单个字符的函数。
一、vue项目搭建 使用vite创建(就不展开了)
二、Ue5.1 像素流-自定义网页 前置条件安装nodejs
可以参考如下
windows下node环境安装
官网教程
https://docs.unrealengine.com/5.1/zh-CN/getting-started-with-pixel-streaming-in-unreal-engine/
1、安装像素流插件
2、打包-文件资源
像素流相关文件夹在引擎资源目录
Engine/Source/Programs/PixelStreaming/WebServers/SignallingWebServer/ 3、配置实例与信令服务器
启动实例: @echo off start Windows/ue5stream.exe -ResX=1920 -ResY=1080 -log -PiexlStreamingIP=localhost -PiexlStreamingPort=8888 -log -RenderOffScreen 可以使用绝对路径 启动信令服务器: @echo off call "SignallingWebServer/run.bat" 4、核心文件
解释说明
webRtcPlayer 是对应原始文件Script/webRtcPlayer.js文件 该文件处理浏览器与虚幻引擎应用间的通信,接受并显示来自服务器的媒体流。
webrtcVideo 是对应Script/app.js文件 此文件包括对键盘、鼠标和触摸事件的事件监听器,还包括数个可在播放器页面使用的函数和钩子。
uevideo.vue集成
<template> <div> <div ref="video" id="player"></div> <!-- <button @click="toUE">向UE发信息</button> --> </div> </template> <script> import { onMounted, ref } from "vue"; import { initLoad, callUIInteraction, addResponseEventListener, } from "../webrtcVideo.js"; export default { setup(props, context) { let video = ref(null); let videoInstance = ref(null); onMounted(() => { console.
微信web开发者工具 C:\Users\xxxxx\AppData\Local\微信web开发者工具\User Data\WeappLog
C:\Users\xxxxx\AppData\Local\微信web开发者工具\User Data\WeappFileSystem
C:\Users\xxxxx\AppData\Local\微信web开发者工具\User Data\Default\Cache
C:\Users\xxxxx\AppData\Local\微信web开发者工具\User Data\WeappApplication
webstorm C:\Users\xxx\java_error_in_webstorm64.hprof
C:\Users\xxx\AppData\Local\JetBrains\WebStorm2020.3\caches\content.dat.storageData
微信 语音缓存:
C:\Users\xxx\Documents\WeChat Files\wxid_xxxxxx\FileStorage\MsgAttach
文件缓存:
C:\Users\xxx\Documents\WeChat Files\wxid_xxxxxx\FileStorage\File
企业微信: C:\Users\xxxxx\Documents\WXWork