我们如何更好的创建和使用索引呢? 大家记住以下这个8个方案就OK啦。
1、只为用于搜索、排序或分组的列创建索引 我们只为出现在WHERE子句中的列、连接子句中的连接列,或者出现在ORDER BY或GROUP BY子句中的列创建索引。仅出现在查询列表中的列就没必要建立索引了。
2、考虑索引列中不重复值的个数 我们知道在通过二级索引+回表的方式执行查询时,某个扫描区间中包含的二级索引记录数量越多,就会导致回表操作的代价越大。==我们在为某个列创建索引时,需要考虑该列中不重复值的个数占全部记录条数的比例。==如果比例太低,则说明该列包含过多重复值,那么在通过二级索引+回表的方式执行查询时,就有可能执行太多的回表,导致性能下降。
对二级索引+回表的这种查询方式还不是太了解的同学请看这篇文章
mysql 回表的代价(InnoDB)
3、索引列的类型尽量小 在定义表结构时,要显示的指定列的类型。以整数类型为例,有TINYINT、MEDIUMINT、INT、BIGINT这几种,他们占用的存储空间大小依次递增。
如果想对某个整数类型的列建立索引,在表示的整数范围允许的情况下,尽量让索引列使用较小的类型,如果能使用INT就不使用BIGINT,因为数据类型越小,索引占用的存储空间就越少,在一个数据页就能存放更多的记录,磁盘IO的性能损耗也就越小,一次页面IO可以将更多的记录加载到内存。
4、为列前缀建立索引 我们知道一个字符串其实是由若干个字符构成的,如果在mysql中使用utf8字符集来存储字符串,则需要1~3个字节来编码一个字符。假如字符串很长,那么存储这个字符串就需要占用很大的存储空间。在需要为这个字符串所在的列建立索引的时候,就意味着在对应的B+树中的记录中,需要把该列的完整的字符串记录下来。字符串越长,在索引中占用的空间也就越大。
其实索引列的字符串前缀也是排好序的,设计索引的人员提出了一个方案,只将字符串的前几个字符存放到索引中,也就是说在二级索引的记录中只保留字符串的前几个字符。创建语句如下:
ALTER TABLE demo_table ADD INDEX idx_key1(key1(10)); //创建的字符串索引只保留前10个字符 5、覆盖索引 为了彻底告别回表操作带来的性能损耗,建议最好在查询的列表中只包含索引列,例如:
SELECT key1,id FROM demo_table WHERE key1 > 'a' AND key1 < 'c'; 由于我们只查询 key1,id列的值,所以在使用idx_key1索引来扫描(‘a’,‘c’)区间中的二级索引记录时,可以直接从获取到的二级索引记录中读出key1列和id列的值,而不需要执行回表操作,我们把这种索引中已经包含所有需要读取的列的查询方式称为覆盖索引。
排序操作也优先使用覆盖索引进行查询,比如:
SELECT key1 FROM demo_table ORDER BY key1; 如果我们的业务中没有必要使用索引列以外的列,或者没有必要使用全部的列,我们最好比需要的列放到查询中,而不是用 select * 代替。
6、让索引列以列名的形式在搜索条件中单独出现 如下的方式并不会使用到索引,而是全表扫描:
SELECT * FROM demo_table WHERE key2 * 2 < 4; 如下的方式可以使用到索引:
SELECT * FROM demo_table WHERE key2 < 4 * 2; 所以,如果想让某个查询使用索引来执行,请让索引列以列名的形式单独出现在搜索条件中。
我们凭什么要用springcloud alibaba? 1、单体应用的痛点
传统的单体应用,将所有功能的表示层、业务逻辑层,数据访问层,包括静态资源等等全部糅合在一个工程里面,编译,打包,部署在单台服务器上上线,比如打成war包放在Tomcat的webapp目录中部署项目。这样的项目开发部署适合小型项目,系统功能不复杂,访问量不大的情况下有绝对的优势。开发速度快,运维方便。但是当业务越来越复杂,功能越来越多,参与的开发人员越来越多,就暴露出问题了。
比如:
业务变复杂,代码量增大,代码可读性,可维护性,可扩展性下降。万一要新同事接手代码,理解起来花很多时间
测试难度增大
单体应用并发能力有限,访问量高了用户体验差
单体应用容错率低,万一哪里出错,可能导致整个项目就崩了
1、微服务的优势
将原来的单体应用按义务范围来进行划分,划分为多个小model,每个微服务运行在自己的进程中,不相互影响,通过完全自动化部署来独立部署。并使用轻量级机制通信,通常是HTTP RESTUFUL API。可对各个微服务进行集中管理。这些小model可以使用不同的编程语言,以及不同的存储技术。
1、springcloud alibaba的重要组件
nacos:
注册中心(服务注册与发现)、配置中心(动态配置管理)
Ribbon:
负载均衡
Feign:
声明式Http客户端(调用远程服务)
Sentinel:
服务容错(限流、降级、熔断)
Gateway:
API网关(webflux编程模式)
Sleuth:
调用链监控
Seata:
原Fescar,即分布式事务解决方案
工程搭建 1、搭建父工程
我们给项目起个名字就叫做’mdx-shop’ 迷迭香的商店
接下来配置下maven
删除掉src目录(父目录不需要)
2、引入相关springcloud依赖
先看下springcloud和springcloud alibaba 和各个组件之间的版本对应关系
引入springboot springcloud spingcloud alibaba 依赖,如下
版本选取:
springboot – 2.6.4
springcloud – 2021.0.1
springcloud alibaba – 2021.0.1.0
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.4</version> </parent> <groupId>com.
安装 1.安装所需软件包
yum install -y yum-utils \ device-mapper-persistent-data \ lvm2 2. 配置源地址
yum-config-manager \ --add-repo \ https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo 3.安装最新版本的dokcer
yum -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin 4.如果需要安装特定版本,则列出并排序您存储库中可用的版本。此示例按版本号(从高到低)对结果进行排序。
yum list docker-ce --showduplicates | sort -r 5.通过其完整的软件包名称安装特定版本,该软件包名称是软件包名称(docker-ce)加上版本字符串(第二列),从第一个冒号(:)一直到第一个连字符,并用连字符(-)分隔。例如:docker-ce-18.09.1。
yum --y install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io 6.启动 Docker服务
systemctl start docker 7.通过运行 hello-world 镜像来验证是否正确安装了 Docker Engine-Community 。
docker run hello-world 卸载 docker 删除安装包:
yum remove docker-ce 删除镜像、容器、配置文件等内容:
rm -rf /var/lib/docker
海内外媒体软文:助力信息传播与品牌建设
在当今数字化时代,企业如何在庞大的信息海洋中脱颖而出,成为品牌建设的领军者?媒体软文投放无疑是一项强大的策略,通过选择合适的平台,精准投放,可以实现信息传播、品牌塑造的双赢效果。本文将深入探讨媒体软文投放的流程,并推荐一款备受好评的软文发稿平台。
媒体软文投放的流程
1. 明确目标与受众
在投放媒体软文之前,企业需明确投放的目标以及目标受众。这有助于选择合适的媒体平台和撰写符合受众需求的软文内容。
2. 选择适宜平台
不同的平台适合不同的品牌和目标。企业可以根据受众特征、行业属性等因素,选择适宜的媒体平台。一些大型新闻门户适合传递权威信息,而社交媒体平台则更适合引发互动与分享。
3. 制定软文内容
根据选择的平台和目标受众,制定具有吸引力的软文内容。内容应当有深度、有价值,能够引发读者兴趣并与品牌形象相契合。
4. 合作与洽谈
与媒体平台建立合作关系,洽谈软文投放的具体细节,包括投放时间、位置、费用等。在此过程中,明确软文的排版、链接形式等细节。
5. 撰写软文
根据合作媒体的要求和软文的主题,撰写引人入胜、内容丰富的软文。注意软文标题的吸引力,以及内容的结构和表达方式。
6. 投放与监测
完成软文撰写后,进行投放并密切监测效果。监测的指标可以包括点击率、转化率、社交分享量等。根据监测结果,及时调整策略,优化软文的传播效果。
如何选择软文发稿平台
在众多软文发稿平台中,如何选择媒体宣发平台。我们通过以下主要特点来判断是否为优质平台:
1. 广泛媒体资源
媒体软文发稿平台需要汇聚了大量的优质媒体资源,涵盖了各类新闻门户、行业媒体和社交平台,可以更好地满足企业的多样化投放需求。
2. 定制化服务
媒体软文发稿需要提供定制化的软文服务,根据企业的需求和目标,量身打造适合的软文策略。从软文撰写到投放,提供一站式解决方案。
3. 数据分析与优化
注重数据分析,提供全面的投放效果监测报告。基于数据的分析,帮助企业了解投放效果,从而进行优化,提升软文传播的效果。
4. 专业团队支持
媒体软文发稿需拥有专业的团队,包括营销专家、撰稿人员和广告策划师。通过专业的支持,能够更好地满足企业在软文投放方面的需求。
媒体软文投放是一项复杂而精细的工作,但在数字化时代,它是企业成功传播信息、树立品牌形象的有效途径。选择适宜的平台,制定精准的内容,结合专业的服务,将是企业成功投放软文的关键。在这一过程中,世媒讯作为软文发稿平台的推荐,以其专业性、广泛媒体资源和定制化服务,为企业提供了一条可行而高效的道路。通过巧妙投放,企业可以实现品牌形象的传播与提升,促进业务的长远发展。
前言 大家好,我是秋意零。今天分析的内容是KVM架构。
👿 简介
🏠 个人主页: 秋意零🔥 账号:全平台同名, 秋意零 账号创作者、 云社区 创建者🧑 个人介绍:在校期间参与众多云计算相关比赛,如:🌟 “省赛”、“国赛”,并斩获多项奖项荣誉证书🎉 目前状况:24 届毕业生,拿到一家私有云(IAAS)公司 offer,目前已在实习💕欢迎大家:欢迎大家一起学习云计算,走向年薪 30 万💕推广:CSDN 主页左侧,是个人扣扣群推广。方便大家技术交流、技术博客互助。 一、KVM组成部分 KVM是硬件虚拟化技术之上构建起来的虚拟机监控器。
不是非要所有这些(CPU、内存、I/O)硬件虚拟化都支持才能运行KVM虚拟化,KVM对硬件最低的依赖是CPU的硬件虚拟化支持,如:Intel的VT技术和AMD的AMD-V技术,而其他的内存和I/O的硬件虚拟化支持,会提高KVM虚拟化的性能。
KVM虚拟化的核心主要由以下两个模块组成:
KVM内核模块:它属于标准Linux内核的一部分,是一个专门提供虚拟化功能的模块,主要负责CPU和内存的虚拟化,包括: 客户机的创建、虚拟内存的分配、CPU执行模式的切换、vCPU寄存器的访问、vCPU的执行。QEMU用户态工具:它是一个普通的Linux进程,为客户机提供设备模拟的功能,包括模拟BIOS、PCI/PCIE总线、磁盘、网卡、显卡、声卡、键盘、鼠标等。同时它通过ioctl系统调用与内核态的KVM模块进行交互。 二、KVM架构图 KVM是在硬件虚拟化支持下的完全虚拟化技术,也就是没有修改过客户机内核的虚拟化,所以它能支持在相应硬件上运行几乎所以的操作系统,如:LInux、Windows、MacOS等。
每个客户机就是一个QEMU进程,在一个宿主机上有多少个虚拟机就会有多少个QEMU进程;客户机中的每一个虚拟vCPU对应QEMU进程中的一个线程;一个宿主机中只有一个KVM内核模块,所有客户机与这个KVM内核模块进行交互。 可以看到图中,最底层是 VT和AMD-V硬件虚拟化技术 -> Linux系统内核包含KVM内核 -> 用户进程和QEMU虚拟机进程。
前言 大家好,我是秋意零。
经过前面章节的介绍,已经知道KVM虚拟化必须依赖于硬件辅助的虚拟化技术,本节就来介绍一下硬件虚拟化技术。
👿 简介
🏠 个人主页: 秋意零🔥 账号:全平台同名, 秋意零 账号创作者、 云社区 创建者🧑 个人介绍:在校期间参与众多云计算相关比赛,如:🌟 “省赛”、“国赛”,并斩获多项奖项荣誉证书🎉 目前状况:24 届毕业生,拿到一家私有云(IAAS)公司 offer,目前已在实习💕欢迎大家:欢迎大家一起学习云计算,走向年薪 30 万💕推广:CSDN 主页左侧,是个人扣扣群推广。方便大家技术交流、技术博客互助。 一、硬件虚拟化技术 硬件虚拟机技术:它是对CPU、内存、I/O等硬件进行的虚拟化技术。
2005年年末lntel发布的VT-x硬件虚拟化技术,以及AMD于2006年发布的AMD-V。
注意:KVM必须需要CPU的虚拟化支持,也就是VT-x和AMD-V。
CPU 虚拟化技术:将一台物理服务器上的 CPU 功能虚拟化,使多台虚拟机可以在同一台物理服务器上运行;内存虚拟化技术:将物理服务器上的内存资源进行划分,使得每一台虚拟机都可以拥有自己的独立内存空间;I/O 虚拟化技术:可以让每台虚拟机独享物理设备,并通过模拟 I/O 设备来完成设备间的数据通信。 注意,I/O虚拟化有四种方式,如下:
设备模拟器:虚拟机监控器中模拟一个传统的I/O设备的特性,比如在QEMU中模拟一个Intel的千兆网卡或者一个IDE硬盘驱动器,在客户机中就暴露为对应的硬件设备。前后端驱动接口:在虚拟机监控器与客户机之间定义一种全新的适合于虚拟化环境的交互接口,比如常见的virtio协议就是在客户机中暴露为virtio-net、 virtio-blk等网络和磁盘设备,在QEMU中实现相应的virtio后端驱动。设备直接分配:将一个物理设备,如一个网卡或硬盘驱动器直接分配给客户机使用,这种情况下I/0请求的链路中很少需要或基本不需要虚拟机监控器的参与所以性能很好。设备共享分配:其实是设备直接分配方式的一个扩展。在这种模式下,一个(具有特定特性的)物理设备可以支持多个虚拟机功能接口,可以将虚拟功能接口独立地分配给不同的客户机使用。如SR-IOV就是这种方式的一个标准协议。 二、Inter硬件虚拟化技术发展 Inter硬件虚拟化技术可以分为3个类别:
VT-x技术:是指Intel处理器中进行的一些虚拟化技术支持,包括CPU中引入的最基础的VMX技术,使得KVM等硬件虚拟化基础的出现成为可能。同时也包括内存虚拟化的硬件支持EPT、VPID等技术。VT-d技术:是指Intel的芯片组的虚拟化技术支持,通过IntelIOMMU以实现对设备直接分配的支持。VT-c技术:是指Intel的I/O设备相关的虚拟化技术支持,主要包含两个技术:一个是借助虚拟机设备队列 (VMDg) 最大限度提高I/O吞吐率,VMDq由Intel网卡中的专用硬件来完成;另一个是借助虚拟机直接互连 (VMDc)大幅提升虚拟化性能,VMDc主要就是基于SR-IOV标准将单个Intel网卡产生多个VF设备,用来直接分配给客户机。 总结 本章中,我们了解到硬件虚拟化技术的支持和发展。
前言 大家好,我是秋意零。
今天介绍的内容是虚拟化技术以及软件虚拟化和硬件虚拟化。
👿 简介
🏠 个人主页: 秋意零🔥 账号:全平台同名, 秋意零 账号创作者、 云社区 创建者🧑 个人介绍:在校期间参与众多云计算相关比赛,如:🌟 “省赛”、“国赛”,并斩获多项奖项荣誉证书🎉 目前状况:24 届毕业生,拿到一家私有云(IAAS)公司 offer,目前已在实习💕欢迎大家:欢迎大家一起学习云计算,走向年薪 30 万💕推广:CSDN 主页左侧,是个人扣扣群推广。方便大家技术交流、技术博客互助。 一、什么是虚拟化? 虚拟化是将我们现实中的计算机硬件资源进行切割,将切割的部分进行使用,这部分的资源被称为虚拟资源。
图中左侧是传统应用方式、右侧是虚拟化应用方式。可以看到右侧是通过Virtual Machine Monitor(VMM)虚拟机监控器,也称为Hypervisor层,就是利用它来达到虚拟化引入的软件层。它向下掌控实际的物理资源(相当于原本的操作系统) ,向上呈现给虚拟机N份逻辑的资源。为了做到这一点,就需要将虚拟机对物理资源的访问“偷梁换柱”一-截取并重定向,让虚拟机误以为自己是在独享物理资源。虚拟机监控器运行的实际物理环境,称为宿主机;其上虚拟出来的逻辑主机,称为客户机。
二、软件虚拟化和硬件虚拟化 软件虚拟化,是通过软件模拟来实现VMM层,通过纯软件的环境来模拟执行虚拟机里的指令。
2.1 软件虚拟化
软件虚拟化技术,通过VMM中间层软件与硬件翻译来实现虚拟化。
最纯粹的软件虚拟化实现当属QEMU。在没有启用硬件虚拟化辅助的时候,它通过软件的二进制翻译仿真出目标平台(计算资源)呈现给虚拟机,虚拟机的每一条目标平台(计算资源)指令都会被QEMU截取,并翻译成宿主机平台的指令,然后交给实际的物理平台执行。由于每一条都需要这么操作一下,其虚拟化性能是比较差的,同时其软件复杂度也大大增加。但好处是可以呈现各种平台给虚拟机,只要其二进制翻译支持。
2.2 硬件虚拟化
硬件虚拟化技术,就是硬件本身支持虚拟化。
硬件虚拟化技术就是指计算机硬件本身提供能力让虚拟机指令独立执行,而不需要 (严格来说是不完全需要) VMM截获重定向。
在x86架构中,它提供一个略微受限制的硬件运行环境供虚拟机运行 (non-root mode),在一般情况下,虚拟机在此受限环境中运行与在宿主机系统运行没有什么两样,不需要像软件虚拟化那样每条指令都先翻译再执行,而VMM运行在root mode,拥有完整的硬件访问控制权限。
可以看到,硬件虚拟化技术性能已经接近于宿主机系统,并且这个过程可以使VMM的软件架构大大简化。
Intel从2005年就开始在其x86 CPU中加入硬件虚拟化的支持Intel Virtualization Technology,简称Intel VT。到目前为止,在所有的Intel CPU中,都可以看到Intel VT的身影。
总结 虚拟化技术可以说是云计算的本质,通过虚拟化技术,我们就可以向使用水电一样使用计算机资源,按需所取、按量收费。
软件虚拟化和硬件虚拟化的区别是,软件虚拟化是通过软件翻译实现的虚拟化,硬件虚拟化是硬件本身支持的虚拟化技术。所有对比性能硬件虚拟化技术更好,因为中间少了一个翻译。
Windows
使用【php-sdk-binary-tools】工具在windows下编译dll扩展。
php-sdk-binary-tools:GitHub - microsoft/php-sdk-binary-tools: Tool kit for building PHP under Windows
编译过程:php mb扩展 windows7,php7.4自定义扩展的编写Windows篇-CSDN博客 注意事项:
config.w32配置【多个cpp的情况下编译】:
ARG_ENABLE('hello', 'hello support', 'yes'); if (PHP_HELLO != 'no') { AC_DEFINE('HAVE_HELLO', 1, 'hello support enabled'); } EXTENSION('hello', 'hello.cpp', null, '/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1'); ADD_SOURCES(configure_module_dirname, "AES.CPP base64.cpp", "hello"); PHP_INSTALL_HEADERS("ext/hello/", "AES.h base64.h"); 如果涉及lib库则在该路径放入头文件和库,测试发现静态的lib库不行诶。
C:\Users\dell\Desktop\php\phpdev\vc15\x64\deps 然后找到Makefile,一般在php源码目录下,文件中的LIBS添加你的lib文件名然后即可编译。
Liunx
config.m4配置【多个cpp的情况下编译】:
dnl In case of no dependencies PHP_REQUIRE_CXX() PHP_SUBST(HELLO_SHARED_LIBADD) PHP_ADD_LIBRARY(stdc++, 1, HELLO_SHARED_LIBADD) AC_DEFINE(HAVE_HELLO, 1, [ Have hello support ]) PHP_NEW_EXTENSION(hello, hello.cpp AES.cpp base64.
前言 今天学习Java8 新特性,主要是之前在学习 Scala、JavaFX 中遇到一些 Lambda 表达式,感觉 lambda 表达式确实很简洁,很有必要学一学,重点是提升逼格,让别人看不懂才是最装的。
目录
前言
1、接口的默认方法与静态方法
编写接口
编写接口的实现类
测试
2、Lambda表达式(重点)
2.1、Lambda 表达式规范
2.1.1、函数接口的定义
2.1.2、Java 内置的函数接口 2.2、Lambda 基础语法
2.2.1、无参方法调用
(1)编写函数接口
(2)使用 lambda 2.2.2、有参方法调用
(1)编写函数接口
(2)使用 lambda 2.3、Lambda 的精简写法
2.3.1、无参方法
2.3.2、有参方法
练习
2.4、Lambda 实战
forEach
集合排序
1、接口的默认方法与静态方法 什么是普通方法?
我们可以把 Java 中的方法看成两类:普通方法(有方法体的)和抽象方法(没有方法体的,需要子类去实现的,比如接口、抽象类)。
JDK8 之前,Java 中接口 Interface 之中可以定义变量和方法:
变量 必须是 public、static、final 的方法 必须是 public、abstract 的 而且这些修饰符都是默认的,也就是不需要我们写。
从JDK8 开始 支持使用 static 和 default 来修饰方法,可以写方法体,不需要子类重写被 static 和 default修饰的方法。
接口中定义的默认方法只有子类对象才能调用,而接口中定义的静态方法只有接口类才能调用。
文章目录 一、前言二、VCCS论文阅读2.1 摘要部分2.2 方法2.2.1 Adjacency Graph2.2.2 Spatial Seeding2.2.3 Features and Distance Measure2.2.4 Flow Constrained Clustering2.2.4.1 k-means算法2.2.4.2 本文的改进 2.3 PCL代码效果以及调参建议 一、前言 我之前狭隘地以为只有点云深度学习才能处理分割问题,偶然发现传统方法的分割结果一样可以令我眼前一亮。这三篇论文原文是:VCCS原文 LCCP原文 CPC原文
其中VCCS是分割前的准备工作,LCCP和CPC是分割的方法,二者论文中的效果图如下,有点出乎我的意料。。。。
传统方法我认为最好的点在于通用性很强,并且可解释,应用起来比较友好。这三篇论文出自同一实验室,并且算法实现均已发布到PCL中,所以我准备学习这三篇论文的方法,并整理成笔记与大家交流。
二、VCCS论文阅读 2.1 摘要部分 在2D图像分割任务中,通常会将相似的像素先聚类成超像素(superpixel),通过这步预处理,可以有效降低后续分割的计算开销。2D超像素在3D中对应超体素(supervoxel),传统方法通过比较颜色和深度的差异来完成超体素的生成,但容易出现跨越物体边界的情况,本文解决这个问题的思路是利用三维几何信息。在3D空间中操作与在投影空间中相比有一明显的优势,投影空间只能处理2.5D的点云(使用RGB-D相机进行一次拍摄),而在3D空间中可以处理3D的情况(使用多个标定好的相机进行拍摄)。实验结果证明了提出方法在抑制跨越边界以及处理速度上的优越表现。
2.2 方法 后文中 V r ( i ) = F 1.. n V_r(i)=F_{1..n} Vr(i)=F1..n,代表分辨率为 r r r的体素云中索引为 i i i的体素,体素用 F F F来描述, F F F是一个 n n n维特征向量,包含了体素的颜色、位置、法线等信息。
2.2.1 Adjacency Graph 构建邻接图是本文提出方法中的关键,对于体素化的三维空间,有三种邻接的定义方式,6-,18-和26邻接,可以用魔方来辅助理解,6邻接包含六个面的中心块,18邻接再包含12个棱块,26邻接则是再包含8个角块。遍历每个体素,使用 3 R v o x e l \sqrt 3R_{voxel} 3 Rvoxel的搜索半径即可完成邻接图的构建
描述 QStandardItemModel类提供了一个通用的模型,用于存储自定义数据。QStandardItemModel可以用作Qt标准数据类型的存储库。它是 Model/View类 之一,是 Qt的model/view框架 的一部分。 QStandardItemModel提 供了一种基于项目的传统方法来处理模型。 QStandardItemModel中的项目是由QStandardItem提供的。QStandardItemModel实现了QAbstractItemModel接口,这意味着该模型可用于在支持该接口的任何视图中提供数据(例如QListView、QTableView和QTreeView,以及自定义视图)。为了提高性能和灵活性,可能希望从QAbstractItemModel中派生子类,以提供对不同种类数据存储库的支持。例如,QDirModel提供了对底层文件系统的模型接口。
当想要一个列表或树时,通常会创建一个空的QStandardItemModel,并使用appendRow()将项目添加到模型中,并使用item()访问项目。如果模型表示一个表格,则通常会将表格的尺寸传递给QStandardItemModel构造函数,并使用setItem()将项目定位到表格中。还可以使用setRowCount()和setColumnCount()来更改模型的尺寸。要插入项目,请使用insertRow()或insertColumn(),要删除项目,请使用removeRow()或removeColumn()。
此外,可以使用setHorizontalHeaderLabels()和setVerticalHeaderLabels()设置模型的标题标签。可以使用findItems()搜索模型中的项目,并通过调用sort()对模型进行排序。调用clear()可以从模型中删除所有项目。
示例1:创建表格 QStandardItemModel model(4, 4); for (int row = 0; row < 4; ++row) { for (int column = 0; column < 4; ++column) { QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column)); model.setItem(row, column, item); } } 示例2:创建树 QStandardItemModel model; QStandardItem *parentItem = model.invisibleRootItem(); for (int i = 0; i < 4; ++i) { QStandardItem *item = new QStandardItem(QString("
文章目录 Scrapy_setting文件配置Scrapy常用参数 Scrapy_setting文件配置 代码未动,配置先行。本篇文章主要讲述一下Scrapy中的配置文件settings.py的参数含义
官文配置参数说明url:
https://docs.scrapy.org/en/latest/topics/settings.html
# Scrapy settings for ScrapyDemo project # 自动生成的配置,无需关注,不用修改 BOT_NAME = 'ScrapyDemo' SPIDER_MODULES = ['ScrapyDemo.spiders'] NEWSPIDER_MODULE = 'ScrapyDemo.spiders' # 这两个默认没有 # 日志保存,需要自己添加 # LOG_FILE="日志名.log" # 日志输出等级 # LOG_LEVEL="WARNING" ''' LOG_LEVEL="WARNING" 就只会WARNING等级之下的ERROR和CRITICAL 1.DEBUG 调试信息 2.INFO 一般信息 3.WARNING 警告 4.ERROR 普通错误 5.CRITICAL 严重错误 ''' # 设置UA,但不常用,一般都是在MiddleWare中添加 USER_AGENT = 'ScrapyDemo (+http://www.yourdomain.com)' # 遵循robots.txt中的爬虫规则 ROBOTSTXT_OBEY = True # 需要改成Flase,要不然很多东西爬不了 # 对网站并发请求总数,默认16 CONCURRENT_REQUESTS = 32 # 相同网站两个请求之间的间隔时间,默认是0s。相当于time.sleep() DOWNLOAD_DELAY = 3 # 下面两个配置二选一,但其值不能大于CONCURRENT_REQUESTS,默认启用PER_DOMAIN # 对网站每个域名的最大并发请求,默认8 CONCURRENT_REQUESTS_PER_DOMAIN = 16 # 默认0,对网站每个IP的最大并发请求,会覆盖上面PER_DOMAIN配置, # 同时DOWNLOAD_DELAY也成了相同IP两个请求间的间隔了 CONCURRENT_REQUESTS_PER_IP = 16 # 禁用cookie,默认是True,启用 COOKIES_ENABLED = False # 请求头设置,这里基本上不用 DEFAULT_REQUEST_HEADERS = { # 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.
在MySQL中,事务隔离级别定义了事务与其他并发事务互相看见对方改变的数据的情况。SQL标准规定了四种隔离级别,具体如下:
序列化(SERIALIZABLE):事务串行执行,即每个事务必须等待上一个事务结束后才能开始执行。这确保了事务之间不会互相干扰,但是也导致了并发性能的降低。可重复读(REPEATABLE READ):在同一个事务内,多次读取同样数据时,结果都是一致的,无论其他事务是否已经修改过这些数据。但是,在事务提交之后,其他事务可以改变数据,这时本事务看到的是修改前的数据。提交读(READ COMMITTED):只能看见已经提交的其他事务所做的修改。换句话说,一个事务开始时,只能看见开始之前已经提交的所有事务所做的修改。本事务内所做的修改在其他事务提交之前是不可见的。未提交读(READ UNCOMMITTED):能看见其他事务做出的未提交的修改。这意味着本事务可能读取到脏数据,即尚未提交的数据。 脏读(dirty read): 当一个事务读取另一个事务尚未提交的修改时,产生脏读;
不可重复读(nonrepeatable read): 同一查询在同一事务中多次进行,由于其他提交事务所做的修改或删除,每次返回不同的结果集,此时发生不可重复读;
幻读(phanton read): 同一查询在统一事务中多次进行,有无其他提交事务所做的插入操作,每次返回不同的结果集,此时发生幻读。
四种隔离级别 隔离级别脏读不可重复读幻读加锁读Read uncommitted 读未提交√√√不加锁Read committed 读已提交×√√不加锁Repeatable read 可重复读 ×××加锁Serializable 可串行化×××加锁 #四种隔离别 -- Read uncommitted 读未提交 脏读 不可重复读 幻读 加锁读 -- Read committed 读已提交 不可重复读 幻读 不加锁 -- Repeatable read 可重复读 不加锁 -- Serializable 可串行化 加锁 -- 查看当前会话隔离级别 SELECT @@tx_isolation -- 查看系统当前隔离级别 SELECT @@global.tx_isolation -- 设置当前会话隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; -- 设置系统当前隔离级别 -- set session transaction isolation level [隔离级别名] 具体实例演示:
一、LinearLayout线性布局 线性布局,即各个模块按照水平或者垂直方向进行排列。通过前几章的学习,大家也大致熟悉了线性布局了,下面的代码,想必大家也都能看懂。最外层的线性布局内部包含了两个线性布局。
layout_width、layout_height表示该线性布局的宽高;
match_parent、wrap_content分别表示匹配上级布局的宽高和模块中内容匹配宽高,即能够刚好完整显示内容。
orientation即表示线性布局的分布方式,vertical表示垂直排列,horizontal表示水平,如果不写该属性,默认为水平排布模式。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="150dp" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="horizontal one!" android:textSize="20sp" android:layout_margin="7dp"/> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="horizontal two!" android:textSize="20sp" android:layout_margin="7dp"/> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" android:text="vertical one!" android:textSize="20sp" android:layout_margin="7dp"/> <TextView android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="2" android:text="vertical two!" android:textSize="20sp" android:layout_margin="7dp"/> </LinearLayout> </LinearLayout> 在最外层的垂直线性布局中包含了两个线性布局,一个水平排列,一个垂直排列,它们内部分别定义了两个TextView显示内容。在水平布局中,定义两个TextView的宽都为0dp,然后定义了权重layout_weight都为1,这样这两个TextView就会根据权重即1/(1+1)=1/2来分配宽度,从效果也可以看到这两个模块平分了宽。而在垂直布局中,则定义了两个TextView的高为0dp,且权重一个为1,一个为2,这样它们则会根据权重1/(1+2)和2/(1+2)来分配高度。效果图如下所示。
二、RelativeLayout相对布局 相对布局表示模块与模块之间的相对位置,如一个模块相对于上一级的左边对齐、右边对齐、位于中间等等;或者一个模块相对于另一个模块位于其左边对齐、右边对齐、顶部或底部等等。
属性较多,我这里就简单列举几个,剩下的大家自己去训练。
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="200dp"> <TextView android:id="@+id/centerinparent" android:layout_width="
1.基本初始化
基本初始化是最常用的结构体初始化方法,通过使用“{}”括号来初始化结构体变量。例如
struct Person { char name[20]; int age; }; struct Person p = {"John", 25}; 2.指定成员初始化
指定成员初始化可以通过指定成员名来初始化结构体的成员变量。例如
struct Person { char name[20]; int age; }; struct Person p = { .age = 25}; 3.常量表达式初始化
常量表达式初始化可以在结构体定义时用常量表达式对结构体成员进行初始化。
struct Circle { int radius; double area; }; const double PI = 3.14; struct Circle c = {5, PI * 5 * 5}; 4. 定义后逐个赋值
struct InitMember { int first; double second; char* third; float four; }; struct InitMember test; test.
从零自制操作系统 保护模式x86寄存器虚拟80806模式何为保护内存地图进入保护模式-第一部分进入保护模式-第二部分 保护模式 x86 X86架构(The X86 architecture)是计算机语言指令集,指intel通用计算机系列的标准编号缩写,也标识一套通用的计算机指令集合
x86是一个intel通用计算机系列的标准编号缩写,也标识一套通用的计算机指令集合,这个x与处理器没有任何关系,它是一个对所有某某86系统的简单的广泛的定义,例如:i386, 586,奔腾(pentium)。由于早期intel的CPU编号都是如8086,80286来编号(都有86),由于这整个系列的CPU都是指令兼容的,所以都用X86来标识所使用的指令集合.如今的奔腾,P2,P4,赛扬系列都是支持X86指令系统的,所以都属于X86家族 。
X86指令集是美国Intel公司为其第一块16位CPU(i8086)专门开发的,美国IBM公司1981年推出的世界第一台PC机中的CPU–i8088(i8086简化版)使用的也是X86指令,同时电脑中为提高浮点数据处理能力而增加的X87芯片系列数学协处理器则另外使用X87指令,以后就将X86指令集和X87指令集统称为X86指令集。虽然随着CPU技术的不断发展,Intel陆续研制出更新型的i80386、i80486直到今天的Pentium 4(以下简为P4)系列,但为了保证电脑能继续运行以往开发的各类应用程序以保护和继承丰富的软件资源,所以Intel公司所生产的所有CPU仍然继续使用X86指令集,所以它的CPU仍属于X86系列。
BIOS是英文"Basic Input Output System"的缩略语,直译过来后中文名称就是"基本输入输出系统"
寄存器 虚拟80806模式 虚拟8086模式又称为虚拟-实模式,允许在保护模式操作系统的控制下执行实模式的程序。
何为保护 保护各个进程所占的内存部分的安全
内存地图 CPU安照内存地图的规则去控制内存的访问
内存中的不同区域可以称之为段(segment)
为了方便CPU管理内存,可以将内存中的每个区域登记到一个表格里(全局描述符表)。然后CPU可以通过全局描述符表(global description table)去了解到该段的一些相关信息
进入保护模式-第一部分 实模式转换到保护模式
只要将CR0寄存器中的PE标志位设置为1,即可进入保护模式
汇编指令为
move eax,cr0 or eax,1 mov cr0,eax 进入保护模式-第二部分 上面三条语句后必须紧跟JMP或CALL指令,否则会出现一些错误
因为当cr0寄存器PE标志位改为1后,将安装32位的形式以流水线方式执行的后面的16位指令,会出现错误,所以此时需要转移指令来对CPU重置一遍
一.利用DNS协议进行隧道穿透 1.环境配置2.Windows系统下进行DNS隧道穿透利用3.Linux系统下进行DNS隧道穿透利用 前文推荐:
《红蓝攻防对抗实战》一. 隧道穿透技术详解
《红蓝攻防对抗实战》二.内网探测协议出网之TCP/UDP协议探测出网
《红蓝攻防对抗实战》三.内网探测协议出网之HTTP/HTTPS协议探测出网
《红蓝攻防对抗实战》四.内网探测协议出网之ICMP协议探测出网
《红蓝攻防对抗实战》五.内网探测协议出网之DNS协议探测出网
《红蓝攻防对抗实战》六.常规反弹之利用NC在windows系统执行反弹shell
《红蓝攻防对抗实战》七.常规反弹之利用NC在Linux系统执行反弹shell
《红蓝攻防对抗实战》八.利用OpenSSL对反弹shell流量进行加密
《红蓝攻防对抗实战》九.内网穿透之利用GRE协议进行隧道穿透
一. 利用DNS协议进行隧道穿透 :
DNS隧道(DNS Tunneling)也是隐蔽隧道的一种方式,通过将其他协议封装在DNS协议中传输建立通信。大部分防火墙和入侵检测设备很少会过滤DNS流量,这就给DNS隧道提供了条件,可以利用它实现诸如远程控制、文件传输的操作。使用dns搭建隧道的工具也有很多,比如dnscat2、DNS2tcp、iodine等。由于iodine工具使用比较稳定,这里使用iodine进行演示,它可以通过一台dns服务器制作一个Ipv4通道,iodine分为客户端和服务端,Iodine不仅有强制密码措施,还支持多种DNS记录类型,而且支持16个并发连接,因此很多时候Iodine是DNS隧道的第一选择。
假设在内网渗透中探测目标服务器,并且我们已经获取到目标服务器主机控制权限,探测DNS协议开放,可以尝试利用DNS隧道工具后续搭建隧道,这里以Iodine工具为案例进行演示,本次实验拓扑如图1-1所示。
图1-1 DNS协议实验拓扑图 1.环境配置 1)使用Iodine工具搭建隧道的前提是有一台服务器和域名,首先进行配置域名解析,为攻击者服务器域名配置两条解析,域名解析配置如图1-2所示,其中A记录类型是告诉dns服务器,域名ns1.xxx.net.cn是由攻击者服务器的公网IP解析,而NS记录类型是告诉dns服务器,域名dc.xxx.net.cn是由dns.ns1.xxx.net.cn解析。
图1-2域名配置 2)如果解析不成功会导致后续DNS隧道无法进行,接下来,我们使用ping命令检测当前环境配置,这里发现可以ping通ns1.xxx.net.cn,说明A记录配置正确,如图1-3所示。
图1-3 ping命令测试配置 3)在攻击者服务器执行tcpdump -n -i eth0 udp dst port 53命令监听本地UDP的53端口。在任意一台主机上执行nslookup dc.xxx.net.cn命令访问域名,如果攻击者服务器监听的端口有查询信息,证明NS记录设置成功,如图1-4所示。
图1-4域名解析配置测试 4)在攻击者服务器进行部署iodine工具,执行yum -y install iodine命令来进行安装,安装完毕后通过执行iodine -v查看版本,如图1-5所示。 图1-5 安装环境 5)下面启动iodine服务端,执行iodined -f -c -P root@Admin123. 192.168.10.1 dc.xxxx.net.cn -DD命令,配置生成虚拟网段,其中-f参数是在前台运行,-c参数禁止检查所有传入请求的客户端IP地址,-P参数指客户端和服务端之间用于验证身份的密码,可以自定义,-D参数指定调试级别,-DD指第二级,"D"的数量随级别增加,这里的IP 192.168.10.1为自定义的虚拟网段,下面实验会通过这个虚拟网段连接服务端,注意网段不要与已存在网段相同,否则会发生冲突连接失败。执行成功则如图1-6所示。
图1-6启动iodine服务端 6)服务端配置成功后会多出一个我们自定义的网卡段,它用来与客户端进行通讯。我们新建一个会话,使用ifconfig命令查看服务器,会发现多出一个虚拟网卡地址,地址为刚设置的地址,如图1-7所示,证明服务端配置成功。
1-7 网卡配置信息 7)我们也可以通过iodine检查页面https://code.kryo.se/iodine/check-it/来检查配置是否正确,输入dc.xxx.net.cn检测,若结果如图1-8所示,则表示设置成功。
图1-8 通过iodine检查页面验证配置成功 2.Windows系统下进行DNS隧道穿透利用 1)下面我们来进行DNS隧道里,假设目标服务器是windows系统,可以使用iodine.exe工具,使用前需要TAP适配器,下载地址为https://swupdate.openvpn.org/community/releases
/openvpn-install-2.4.8-I602-Win10.exe,下载后直接在目标服务器安装,如图1-9所示。
图1-9 安装TAP适配器 2)在目标服务器执行iodine.exe -f -r -P root@Admin123.
文章目录 前言1 翻译报错代码2 搜索报错代码3 使用GPT进行纠错4 使用Gitee或Githup排错5 总结代码报错解决方法一:翻译报错代码,看能不能在代码提示中找到解决方法二:当你看过报错代码后依旧没有解决就可以搜索了,推荐使用必应,并且使用插件三:搜索依旧没有解决就使用GPT四:最后看Gitee或者Githup上关于你的项目源码 6 报错分享 前言 代码报错靠自己悟估计要到猴年马月了
互联网99.9999%有关于自己python代码报错的解决方法,但是怎么搜索呢,或者说怎么排错
这里推荐自己解决报错的几种方法
保证大家看完后遇到代码报错一定学会并且解决代码报错
注意:
如果遇到代码没有报错,但是代码是错误的情况
这个情况比代码报错还要烦,因为代码报错有提示,他连提示都没有
那么你只能使用下面2,3,4的解决方法
也可以在评论区分享你的报错代码
1 翻译报错代码 代码报错的格式都是固定的,比如:
IndexError: list index out of range
报错类型:报错提示
他都是有提示,我们可以直接翻译,使用pycharm插件可以直接翻译
报错代码:
li = [2] print(li[2]) 可以看到 File “X:\009_接单\python解决代码报错\test1.py”, line 2, in 这句的意思就是 在 "X:\009_接单\python解决代码报错\test1.py"这个文件中,在第二行报错了
(如果报错文件不是你运行的文件,不用看,都是安装的模块文件,你只需要看你自己的文件就行)
翻译后可以看到是因为列表超出索引范围导致的,那我们把列表的下标改就行
li = [2] print(li[0]) 但是有些报错就算翻译后也解决不了
所以就只能在互联网找教程或者报错解决方法
2 搜索报错代码 报错代码搜索也是一个解决方法,但是如果你的搜索关键词不精准也是搜索不到自己的错误代码的
都是与自己代码错误无关的文章
搜索报错代码的格式,我自己常用的搜索方法
例如:
python execjs AttributeError: ‘NoneType’ object has no attribute ‘replace’ 报错
这样搜索的返回结果就是关于python execjs模块报错AttributeError: ‘NoneType’ object has no attribute 'replace’的相关文章,更加精准
前言: 欢迎来到 STM32CubeIDE 的精彩世界!STM32CubeIDE是一款由STMicroelectronics提供的强大的嵌入式开发工具,它基于Eclipse集成开发环境,提供了丰富的功能和工具来简化STM32微控制器的开发过程。本篇博客将带你逐步学习如何在STM32CubeIDE中进行按键输入的基本应用。
步骤一:创建新工程 首先,打开STM32CubeIDE并点击“File” -> “New” -> “STM32 Project”以创建一个新的工程,选择你的STM32微控制器型号。
步骤二:配置引脚 在工程创建完成后,点击"Pinout & Configuration"选项卡,配置时钟、调试方式、LED灯、按键的引脚。选择你所使用的引脚作为按键输入,并设置相应的模式为输入。
配置调试方式
配置外部高速时钟
设置时钟位72MHZ
配置按键GPIO口,并设置上拉
配置LED灯
生成工程
步骤三:编写代码 在"Project Explorer"中,找到main.c文件。在主循环中编写按键检测的代码。下面是一个简单的例子,这里使用的是GPIOE的Pin4作为按键:
while (1) { if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0){ //检测按键是否按下 while(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0); //确定按键按下 HAL_Delay(10); //按键消抖 HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5); //LED灯翻转 } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } 步骤4:编译与烧录 编写完代码后,点击工具栏上的“Build”按钮进行编译。编译成功后,连接你的STM32开发板,点击“Run”按钮进行烧录。
video_20231111_185544
总结 通过这个简单的入门教程,你或许已经学会了如何在STM32CubeIDE中创建一个按键输入的基本工程。当然,这只是一个起点,你可以进一步扩展代码以处理更多按键事件,甚至可以结合其他外设和功能进行更复杂的嵌入式开发。
希望这篇教程能够帮助你顺利开始使用STM32CubeIDE进行按键输入的开发,祝愿你在嵌入式领域取得成功!
FPGA驱动WS2812B 近期准备复现紫光的视频氛围灯,现在学习了如何驱动WS2812B
将实现任意灯的点亮以及流水实现。
目录 FPGA驱动WS2812B原理代码效果 原理 这个灯带每个灯珠里面都有一个芯片控制,只要按照一定的时序发送数据即可控制其亮灭。
只要把24位RGB一位一位发送出去即可,也就是只要发送0码或者1码,按顺序发送24个即可。
下面是发送时序。
很明显 0码和1码并不是说给个低电平或者高电平就行,而是给一个占空比不同的pwm波,比如0码就是给220ns380ns的高电平再给580ns1.6us的低电平即可。1码同理。 而reset码就是280us的低电平。
可以先发送N组24bit的数据再接一个reset信号表示一组结束
高位在前低位在后格式是GRB。
代码 代码也参考了别人的设计框架,利用三段式状态机,只要修改一些参数即可实现点亮任意灯和流水的间隔。
//GRB顺序点亮 //实现任意灯珠的点亮 //同时实现流水灯 module ws_2812_crtl ( input wire clk , input wire rst , //input wire [23:0] led_state , output wire led //输出led信号 ); //灯珠数量 parameter LED_NUM =5; parameter FREQ =50_000_0; //100ms加一次 也就是频率10HZ wire clk_74; wire locked; clk_wiz_0 clk_74_25 ( // Clock out ports .clk_out1(clk_74), // output clk_out1 // Status and control signals .
释放Node.js的潜力:NVM指南,让版本管理变得轻松 前言第一:NVM简介1. 什么是 NVM?2. 为什么我们需要 NVM?3. NVM 的基本概念: 第二:NVM在各大系统的安装与使用1. 在 macOS 上安装和配置 NVM:步骤: 2. 在 Linux 上安装和配置 NVM:步骤: 3. 在 Windows 上安装和配置 NVM:步骤: 4. 配置 NVM:常用命令: 注意事项: 第三:基础用法1. 安装 Node.js 版本:2. 列出已安装的 Node.js 版本:3. 切换全局 Node.js 版本:4. 设置默认 Node.js 版本:5. 卸载 Node.js 版本:6. 在项目中使用指定版本: 第四:版本切换1. 版本切换原理:2. 在项目中应用版本切换:步骤: 3. 自动版本切换:4. NVM 切换策略: 第五:默认版本配置1. 查看已安装的 Node.js 版本:2. 设置默认版本:3. 验证默认版本:注意事项: 第六:nvm别名1. 查看已安装的 Node.js 版本:2. 设置别名:3. 使用别名:4. 删除别名:注意事项: 第七:nvm常用插件1. avn:2. nvm-windows:3. nvm-fish:4. nvm-completion:5. nvm-lazy: 前言 在Node.
当我们开始学习js后,终于要实现更加完善的轮播图了。但是这时我们难免会有些没有思路,所以我在此为大家提供一些轮播图的思路。
首先,我们想要做轮播图,需要了解一些所需要的相关方法。
window.setTimeout(): 这个方法的意义是在设定时间过后执行目标函数。
这个方法有两个参数。第一个:传入一个function,用来设定执行的目标函数;第二个:传入一个数字(单位:毫秒)设定多久后执行目标函数。
取得元素节点对象的相关方法 document.getElementsByxxx() 通过元素类名/ID/标签名等获取.
document.querySelector() or document.querySelectorAll() 通过选择器选取(传入一个字符串,字符串里写选择器,注意一定要按选择器的形式来写),前者仅选择第一个元素,后者选取所有元素。
注意:无论是那种方法取得的是多个元素,其返回的都是一种“伪数组”。伪数组就是你可以像数组一样通过索引来取得元素,例如:document.getElementsByClassName("a")[0] 但是 不能使用数组的方法(因为不是数组,所以肯定不能用)。
轮播图原理 上面我们先了解了一些实现轮播图可能会用到的方法。现在我们来聊一下轮播图的原理。
实现轮播图,我们肯定要修改其css属性,如何修改就要看轮播图的实现方式。
我通过正常的轮播图来举例:通过修改内层盒子的margin-left值来使内层盒子相对外层盒子运动,从而实现轮播图效果。
相信对于轮播图效果的实现大家都能快速理解,且对于其他类型诸如渐入渐出轮播图等都是差不多的。就算实现自动切换,也不过是设置一个动画的事罢了。但是难点就在于把手动切换和自动切换结合在一起,这时就会有难点产生。
首先,如果使用动画来使轮播图自动切换,是无法再进行手动切换的。所以我们就需要通过js来实现其自动切换。自动切换可以用setInterval()来实现(这个函数与setTimeout基本一致,区别仅在于setTimeout只会在设定时间到后执行一次,而setInterval会在每过设定时间都会执行一次),设定一个change方法来切换下一张轮播图,让setInterval每过一段时间调用一次来切换即可。这样写基本就能结合手动切换和自动切换,但是有一个小问题,就是如果马上就要到执行setInterval的时间,但是我手动点击切换了一次,就会导致刚切换到我想看的那张轮播图,就会立刻切换到下一张。为了解决这个小问题,我们可以这样写(此方法作为所有切换的方法,只要是这个同一个轮播图的切换,都调用这同一个方法)
function change(i){ /*当没有传入参数时调用此方法就会切换下一张*/ if(i == undefined){ index++;//index是一个去全局变量,表示当前显示的轮播图是第几张 }else{ index = i; } /*判断是否越界*/ if(index < 1) index = max;//max表示最多轮播图的张数 if(index > max) index = 1; //根据index修改css属性,此处以正常轮播图为例 //此处需要注意 //1.必须使用负值,为何是负值可以看着上面那个图自己思考一下 //2.最后一定要加上"px",因为这个值直接修改了其css属性,所以必须按照css的写法来写 //imgWidth就是每张轮播图图片的宽度 inner.style.marginLeft = -index*imgWidth +"px"; //这里是重点! clearTimeout(pre); pre = setTimeout(change,1000); } 让我们来解析一下重点部分的代码:clearTimeout这个方法的意思是清除一个定时器(setTimeout生成的,如果执行过了,执行清除不会报错,但是没有意义)而其参数就是setTimeout返回的一个数字,这个数字就如同这个定时器的id。
每次切换图片时,我们都会调用一次此方法,如果是自动切换,就会在每次切换时,清除一次定时器,但是由于定时器正在执行,实际上此次清除是无意义的;之后再执行setTimeout再次设置定时器,从而形成一个循环。
如果定时器还未执行,此时点击就会将正在准备的定时器清除,并创建一个新的定时器。
注意:想要页面开始就触发自动播放,可以在js最后加一句change(1);也就是切换到第一张,同时开启了循环。
在YOLOv6 初版出来不久,YOLOv7就立马横空出世了。与YOLOv5、YOLOv6不同,YOLOv7是由YOLOv4团队的原班人马提出的(官方出品)。从论文的表上来看,目前YOLOv7无论是在实时性还是准确率上都已经超过了当时已知的所有目标检测算法。并且它在COCO数据集上达到了56.8%的AP。
文章目录 1、YOLOv7介绍1.1、创新点1.2、详细设计1.2.1、聚合网络设计1.2.2、卷积重参化1.2.3、基于concatenate的模型缩放1.2.4、标签分配1.2.5、训练时的其它策略 1.3、实验结果 2、测试2.1、官方脚本测试2.2、opencv dnn测试2.3、测试统计 3、Opencv dnn 批量推理 1、YOLOv7介绍 1.1、创新点 模型结构重参化和动态标签分配已经成为了目标检测领域中的主要优化方向。针对于结构重参化,作者
通过分析梯度的传播路径来为网络中的不同层进行结构重参化优化,并且提出了不同规划的模型结构重参化。在动态标签分配上,因为模型有多个输出层,所以在训练时就难以为不同的分支分配更好地动态目标。所以作者提出了一个新的动态标签分配办法:coarse-to-fine,即由粗到细引导标签分配的策略。
还提出了扩展和复合缩放的方式,通过这种方式可以更高效利用参数量和计算量。这样不仅可以减少大量参数,还可以提高推理速度以及检测精度。
并且设计了几个可以训练的bag-of-freebies。这样使得模型在不更改本身结构时,大大提高检测精度。
1.2、详细设计 1.2.1、聚合网络设计 为了增强网络的实时性检测,YOLOv7里使使用VoVNet的变体CSPVOVNet。不仅考虑模型的参数量、计算量、内存访问次数、输入输出的通道比、element-wise操作等方面分析参数的数量、计算量和计算密度,还分析了梯度的在模型中流动路径,通过这个来使得不同层的权重能够学习到更加多样化的特征。
还提出了基于ELAN的Extended-ELAN,也就是E-ELAN方法。通过高效长程注意力网络来控制梯度的最短最长路径,让更深的网络可以更加高效地学习和收敛。作者提出的E-ELAN使用expand、shuffle、merge cardinality来实现在不破坏原有梯度路径的情况下,提升网络的学习能力。无论梯度路径长度和大规模ELAN中计算块的堆叠数量如何,网络都能够达到稳定状态,但是倘若继续这样一直地堆叠这一些计算块下去,反而可能会破坏这种稳定的状态,从而导致降低参数的利用率。
在结构方面,E-ELAN只改变块本身的架构,对于过渡层的架构则没有改变,这边的调整策略是使用组卷积来扩展计算块的通道和基数,将对计算层的所有计算块应用相同的组参数和通道数,然后,对于每个计算块输出的特征图会根据设置的组参数g被随即打乱成g个组,之后再将它们连接在一起。注意到这个时候,每组特征图的通道数和原来架构中的通道数是一样的,最后,添加g组的特征图来执行合并基数。E-ELAN除了保持原有的ELAN设计架构外,还可以帮助其它组的计算块学习到更加多样化的特征。
1.2.2、卷积重参化 重参化技术是模型在推理时将多个模块合并成一个模块的方法,其实就是一种集成技术。常见的重参化技术有:
一种是用不同的训练数据训练多个相同的模型,然后对多个训练模型的权重进行平均。一种是对不同迭代次数下模型权重进行加权平均。 然RepConv在VGG上取得了很不错的效果,但将它直接应用于ResNet和DenseNet或其他骨干网络时,它的精度却下降得很厉害。作者就是用梯度传播路径的方法来分析,因为RepConv结合了3×3卷积,1×1卷积,和在一个卷积层中的identity连接,可是这个identity破坏力ResNet的残差连接以及DenseNet的跨层连接,为不同的特征图提供了更多的梯度多样性。
因此,作者认为,在同时使用重参化卷积和残差连接或者跨层连接时,不应该存在identity连接,而且作者还分析重参数化的卷积应该如何与不同的网络结构相结合以及设计了不同的重参数化的卷积。
1.2.3、基于concatenate的模型缩放 模型缩放是调整模型的大小来生成不同尺度的模型,用于满足不同场景下的推理需求。如今的网络中,主要的缩放因子有input size、depth、width、stage,通过控制这些参数,模型的参数量、计算量、推理速度和精度都有一个很好的平衡。同时,网络架构搜索NAS技术也经常使用到。
作者还发现使用concatenate模型时,不能单独地分析缩放因子的影响,还必须结合通道数的变化一起分析,因为在这过程中会导致输入通道和输出通道的比例会发生变化,从而导致模型的硬件使用率降低。还提出了一种复合缩放方法,这样不仅可以保持模型在初始设计时的特性还可以保持性能最佳时的结构。
1.2.4、标签分配 但近年来,需要研究者会利用网络的推理结果来结合GT,去生成一些软标签,如IOU。在YOLOv7中,有辅助头也有引导头,在训练时,它们二者都需要得到监督。因此,需要考虑如何为辅助头和引导头进行标签分配。因此在这里,作者提出了一种新的标签分配方法,是以引导头为主,通过引导头的推理来指引辅助头和自身的学习。
使用引导头的推理结果作为指导,生成从粗到细的层次标签,分别用于辅助头和引导头的学习。为了使那些超粗的正网格影响更小,会在解码器中设置限制,来使超粗的正网格无法完美地产生软标签。通过以上的机制,允许在学习过程中动态调整细标签和粗标签的重要性,使细标签的始终优于粗标签。
1.2.5、训练时的其它策略 Batch Normalization:
即将Batch Normalization层直接连接到卷积层中。这样可以在推理时将Batch Normalization的均值和方差直接融合到卷积层的偏差和权重中。
YOLOR中结合隐性知识和卷积特征图的加法和乘法方法
在YOLOR中,它认为隐式知识可以在推理时通过预计算步骤被简化为向量。然后再把这个向量和前一个或后一个卷积层的偏差和权重融合在一起。
EMA:
EMA是一种在mean teacher中使用的技术,在系统中使用EMA模型纯粹作为最终的推理模型。EMA可以用来估计变量的局部均值,使得变量的更新与一段时间内的历史取值有关,这里可以取得平滑的作用。如果取n步的平均,就能使得模型更加得鲁棒。
1.3、实验结果 作者为边缘GPU、普通GPU、高性能云GPU三种不同场景设计了三种模型,分别是YOLOv7-Tiny、YOLOv7和YOLOv7-W6。并且通过论文中的复合缩放方法,对整个模型的深度、宽度进行缩放,得到了YOLOv7-X、YOLOv7-E6和YOLOv7-D6。以及在YOLOv7-E6基础上使用了E-ELAN技术来获得YOLOv7-E6E。
可以看到以下和其他目标检测器的速度、精度对比结果。
2、测试 以模型 YOLOv7.pt 为例进行测试 下载链接
2.1、官方脚本测试 使用默认脚本参数,设置--device 0使用GPU加速对目录中的所有图片进行推理。代码中当使用GPU加速时,提前进行了warmup。
(yolo_pytorch) E:\DeepLearning\yolov7>python detect.py --weights yolov7.pt --source inference/images --device 0 Namespace(weights=['yolov7.pt'], source='inference/images', img_size=640, conf_thres=0.25, iou_thres=0.
这次介绍统信1060系统的pxe安装,介绍完后pxe的部署也算是告一段落了,后期看缘分介绍windows的部署(WDS)。
镜像准备 直接官网下载,按照自己的平台芯片下载对应的镜像【uos-desktop-20-professional-1060-arm64.iso】
下载后将镜像文件解压到/uos_folder/目录下 mkdir -p /uos_folder mkdir -p /mnt/tmp mount /home/uos-desktop-20-professional-1060-arm64.iso /mnt/tmp cp -r /mnt/tmp /uos_folder/uos_arm_1060 tftp内核准备 mkdir -p /var/lib/tftpboot/boot/uos_arm_1060/ cp /mnt/tmp/live/vmlinuz /var/lib/tftpboot/boot/uos_arm_1060/ cp /mnt/tmp/live/initrd.img /var/lib/tftpboot/boot/uos_arm_1060/ umount /mnt/tmp NBP准备 同样是arm系统,可以使用之前kylin的NBP file就可以了,同架构都是通用的,放好之后改一下dhcp策略就行了。
grub文件准备 vi /var/lib/tftp/grub/grub.cfg ### default=autoinstall timeout=5 timeout_style=menu d=autoinstall menuentry "Auto - uos_arm_1060 - Installer" { echo "Start install uos_arm_1060" echo "Loading Kernel..." linux /boot/uos_arm_1060/vmlinuz console=tty boot=live netboot=nfs nfsroot=xx.xx.xx.xx:/uos_folder/uos_arm_1060/ components union=overlay locales=zh_CN.UTF-8 livecd-installer ubiquity/reboot=true -- echo "Loading Ram Disk.
USB-C PD协议里,SRC和SNK双方之间通过CC通信来协商请求确定充电功率及数据传输速率。当个设备需要充电时,它会发送消息去给适配器请求充电,此时充电器会回应设备的请求,并告知其可提供的档位功率,设备端会根据适配器端回应的信息请求调整本身的功率需求,并通过CC去请求协商确定最终的充电功率
在OTG模式下,USB-C接口可以用于连接外部设备,例如SD(读卡器)、音频、U盘、鼠标等。当设备处于OTG模式下时,并且需要充电的时候,它可以同时向适配器发送充电请求且和外部设备进行数据交互的一个过程。
为了实现在数据交互的同时需要满足设备的供电需求,充电器需要支持PD协议,并且能够提供设备端需要的功率。同时,设备端也需要支持PD协议并且能够同时进行充电和OTG数据传输。双方只有满足以上这些条件时才能够实现在充电的同时进行数据交互,也就是上述提到的OTG模式
二、USBPD充电原理
USB-PowerDelivery(USBPD)是由USB-IF安排拟定的现在干流的快充协议之一,它能够使现在默许最大功率5V/2A的type-c接口进步到100W功率。而且能够进行双向乃至组网的电能传输,具有体系级供电计划。
USBPD通讯经过VBUS上沟通耦合的FSK信号的调制(24MHz)进行半双工通讯,然后完成手机和充电器的充电进程。
SOURCE端和SINK端别离代表适配器端和手机内部芯片SINK操控器,从USB通讯传输视点能够理解为USBHOST(主设备)和USBOTG(做从设备)。
当电缆接通之后,PD协议的SOP通讯就开端在CC线(type-c接口通讯装备通道)上进行,以此来挑选电源传输的标准,此部分由SINK端向SOURCE端问询能够供给的电源装备参数(5V/9V/12V/15V/20V)。
USBPD通讯经过VBUS上沟通耦合的FSK信号的调制(24MHz)进行半双工通讯,然后完成手机和充电器的充电进程。
SOURCE端和SINK端别离代表适配器端和手机内部芯片SINK操控器,从USB通讯传输视点能够理解为USBHOST(主设备)和USBOTG(做从设备)。
当电缆接通之后,PD协议的SOP通讯就开端在CC线(type-c接口通讯装备通道)上进行,以此来挑选电源传输的标准,此部分由SINK端向SOURCE端问询能够供给的电源装备参数(5V/9V/12V/15V/20V)。
1、概述
LDR6023SQ QFN-16 是乐得瑞科技针对 USB Type-C 标准中的 Bridge 设备而开发的双 USB-C DRP 接口 USB PD 通信芯片。具备 Power Negotiation 数据包透传功能,切换 Data Role 功能,以及通过 VDM 协商让智能设备进入 ALT MODE 的功能,并针对各大手机品牌的 USB-C 兼容性进行了特别优化,适合于手机音频转接器应用场景。
2、特点
◇ QFN-16_3x3 小封装
◇ 支持 USB PD 2.0,兼容 USB PD 3.0
◇ 支持 QC2.0,兼容 QC3.0
◇ 透传适配器与智能设备(电脑,平板,手机)之间的 PDO 及 REQUEST 协商
◇ 自动进行 DR_SWAP 转为 UFP 模式
◇ 提供外设复位控制功能,为外设提供复位信号
文章目录 一、简介二、准备工作2.1 安装PCL 1.11.12.2 安装Visual Studio 2019 三、配置方法四、结论 一、简介 pcl是应用最广泛的点云处理库之一,使用pcl也是进行相关领域科研或者找相关工作必备的一个技能点。pcl的配置方法网上一抓一大把,回想我大四最开始接触点云的时候,也是照搬博客里的操作一步一步完成了配置,但很多步骤是在做什么其实都不懂。现在是研一下,这段时间也做了一些小项目,学了一些新操作,也大概能理解这些步骤到底是在做什么。写这篇文章的目的就是给跟我一样在配置pcl时候知其然又想知其所以然的编程小白做一些普及,说不定哪句内容就会解答你之前的一个疑惑(内容很浅显,大佬请绕道)
并且本文废话比较多,如果只是想完成配置,可以看下面的博客:Windows + VS2022超详细点云库(PCL)配置
二、准备工作 2.1 安装PCL 1.11.1 首先进入https://github.com/PointCloudLibrary/pcl/releases,到2023年5月18日,PCL已经更新到了1.13.1版本,并且还有人在持续维护,这种我就很喜欢:) ,关于PCL版本的选择,我的建议是先选1.11及以前的。因为1.12中对一个点云数据结构进行了更改,如果你用了这个版本,就会惊奇的发现网上大部分的教程运行起来会报内存错误,这肯定不适合刚入门的来折腾,所以干脆直接安低版本的吧~
以1.11.1版本为例,github上的发行包长成这样子
需要关注这几个文件
AllInOne.exe:这个文件可以安装pcl以及其第三方依赖库。需要注意,文件名中包含msvc2019,代表这个版本的库是使用msvc2019版本的编译器编译的,由于不同版本的编译器的输出结果可能有不兼容,所以我们要安装和这个编译器版本匹配的Visual Studio版本,自然接下来我们要安装Visual Studio 2019。pdb.zip:后面我们可以看到,AllInOne的安装结果是一堆dll库,如果某天你对某个pcl模块的内部实现非常感兴趣,想起了C语言老师的教导“要记得使用单步调试来学习代码”,你就会惊奇的发现,pcl的函数没有办法调试进入,问题可能就出在你没有安装pdb。 pdb是Progam Debug DataBase,显然他是一个与debug有关的文件,会在编译dll的同时生成 。pdb通常会用在协作开发中,A封装了A.dll,B封装了B.dll,如果发布的应用程序出现了未知错误,运行程序崩溃时生成的dump文件,配合A和B提供的pdb文件,就可以很快定位到究竟是谁写的哪行代码出现了bug,这时候主管就会找你来追责啦:)。如果没有这文件,那就只能凭客户的描述来猜究竟是哪里出了问题,效率很低。但好像有了pdb文件就可以反编译了,所以要注意只能在内部使用噢 Source code:这里是PCL的源码。如果你需要换一个编译器,这时候就要对源码进行编译了,这部分怎么搞之后再说。 记得添加环境变量
记得修改安装路径,并记住! 安装过程中如果遇到OpenNI的问题,可以不用管,后边找到OpenNI的位置,然后单独安装到3rdParty文件夹中即可。 安装完成后的文件结构如下
3rdParty中包含PCL的依赖库,其中最重要的几个 Boost(必须):PCL中使用了boost中的共享指针和线程操作Eigen(必须): 方便的进行矩阵运算FLANN(必须):用来实现点云处理中的重要步骤——K近邻搜索VTK(必须):用于点云的渲染和可视化 bin文件夹中是构建生成的一些文件,包含例程的可执行文件以及一堆dll库,注意这里有两种dll库,一种是用于Debug模式文件名以d结尾,另一种是用于Release版本,这个后边配置的时候要注意与使用的模式相匹配。cmake:我们因为不使用cmakelist,所以这部分可以先不用关注include文件夹里是dll对应的头文件lib是dll库的引入库,这部分之后会详细说明share里是相关文档 将pdb压缩文件解压到bin文件夹下,与dll文件放到一起
2.2 安装Visual Studio 2019 刚才提到了,我们选择的PCL版本是1.11.1,官方使用了msvc2019编译器预先对源码进行了编译以方便开发者的使用,所以我们安装VS 2019来避免一些未知错误,这个安装方法更是一抓一大把,也没啥内容,你奶奶来了都能安上,我就不写了。
说句题外话,网友总是会对哪种编译器更好产生争论,这个我认为duck不必,用的顺手比啥都强。但对于初学者,我非常建议直接使用Visual Studio来进行开发,虽然其总因为巨大的体量和复杂的工程被广大程序员看不起,但的的的确确确可以减少很多配置步骤,并且功能齐全。咱还是把时间花到刀刃上,别纠结咋配置环境了吧:)
三、配置方法 创建一个新工程右键工程名,点击最下边的属性(Properties)修改最上方模式,我这里选择的是Release和x64选择Configuration Properties–>VC++ Directories 修改Include Directories,指定这个是为了编译器可以找到我们#include的头文件,因此我们需要在这里添加pcl以及第三方依赖库的头文件路径,一般会放在include文件夹中,以我的路径为例,需要添加以下路径,需要结合自己的路径进行修改 D:\PCL1.11.1\PCL 1.11.1\include\pcl-1.11 D:\PCL1.11.1\PCL 1.11.1\3rdParty\Boost\include\boost-1_74 D:\PCL1.11.1\PCL 1.11.1\3rdParty\Eigen\eigen3 D:\PCL1.11.1\PCL 1.11.1\3rdParty\FLANN\include D:\PCL1.11.1\PCL 1.11.1\3rdParty\VTK\include\vtk-8.2 D:\PCL1.11.1\PCL 1.11.1\3rdParty\OpenNI2\Include 修改Library Directories, 指定这个是为了编译器可以找到dll的引入库,注意Eigen因为是纯模板库,所以不需要指定(TODO:这个模板库是咋回事现在还没太搞懂) D:\PCL1.
前言 欢迎来到 STM32CubeIDE 的世界!如果你对嵌入式开发、STM32微控制器和CubeIDE工具感兴趣,那么你来对地方了。本篇博客将带你一步一步的创建和配置你的第一个 STM32CubeIDE 工程,让你迅速踏上嵌入式开发的旅程。
步骤一:安装STM32CubeIDE 首先,确保你已经在你的计算机上成功安装了 STM32CubeIDE。你可以从ST官方网站下载安装包并按照安装向导进行安装。
步骤二:启动STM32CubeIDE 安装完成后,启动 STM32CubeIDE,选择一个保存工程的文件夹,进入到欢迎界面后,你就可以开始选择创建一个新的工程了。
步骤三:选择MCU型号 在新建工程向导中,选择你所使用的 STM32 微控制器型号。CubeIDE 支持众多不同型号STM32 微控制器,确保选择与你拥有的硬件相匹配的型号,我这里使用的是STM32F103ZET6。
步骤四:配置工程参数 在这一步,你需要配置工程的一些基本参数,比如工程的名称、位置以及使用的编程语言等。确保填写准确,方便后续的开发工作。
步骤五:配置时钟与外设 接下来,你需要配置时钟和外设。这是非常关键的一步,因为正确的时钟配置和外设初始化是保证系统正常运行的关键。CubeIDE 提供了直观的图形化配置界面,方便你进行相关设置。
步骤六:生成工程代码 配置完成后,点击“Finish”按钮。CubeIDE 将根据你的配置生成相应的工程代码。
可以在左侧查看到生成的代码
步骤七:编写你的第一个程序 恭喜你,你已经成功创建并配置了你的第一个 STM32CubeIDE 工程!现在,你可以开始编写你的第一个程序了。在工程中找到 main.c 文件,这是程序的入口。随意编写一些简单的代码,比如在while循环里编写一个500ms翻转一下 LED的程序。
while (1) { HAL_GPIO_TogglePin(GPIOE, GPIO_PIN_5); HAL_Delay(500); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } 点击这个小锤子,编译整个工程。没有报错,然后下载程序到开发板上
步骤八:演示视频 video_20231110_144554
总结 通过这个简单的入门教程,你已经学会了如何在 STM32CubeIDE 中创建和配置一个基本的工程。在未来的教程中,我们将深入探讨如何使用 CubeIDE 进行更复杂的开发,包括外设的驱动、中断处理等。希望这篇教程能够帮助你顺利入门 STM32CubeIDE,享受嵌入式开发的乐趣!
文章目录 前言问题展示分析及解决办法UTF-8和UTF-8-SIG的区别避免乱码的注意事项1.确认编码2.避免非标准字符3.校验数据4.使用合适的库 前言 本期主要带来Python 程序采集到的数据,保存成 CSV 格式的文件时出现了乱码的解决办法
问题展示 with open('beike.csv','a+', newline='',encoding='utf-8') as file: 分析及解决办法 encoding是编码的意思,在python中,Unicode类型是作为编码的基础类型。
这是由于文件的编码格式和python默认的编码格式不一致导致的,只需要将编码格式utf-8改为utf-8-sig即可
with open('beike.csv','a+', newline='',encoding='utf-8-sig') as file: UTF-8和UTF-8-SIG的区别 1、”utf-8“ 是以字节为编码单元,它的字节顺序在所有系统中都是一样的,没有字节序问题,因此它不需要BOM,所以当用"utf-8"编码方式读取带有BOM的文件时,它会把BOM当做是文件内容来处理, 也就会发生类似上边的错误.
2、“uft-8-sig"就是"带有签名的utf-8”, 因此"utf-8-sig"读取带有BOM的"utf-8文件时"会把BOM单独处理,与文本内容隔离开,也是我们期望的结果.
避免乱码的注意事项 为了避免乱码问题,可以注意以下几点:
1.确认编码 在读取和写入CSV文件时,要确保使用的编码方式与文件本身的编码方式一致。常见的编码方式有UTF-8、GBK等。
2.避免非标准字符 如果数据中包含非标准字符,可能会导致乱码问题。在处理CSV文件时,要确保数据符合所使用的编码规范,避免使用非法字符。
3.校验数据 对于从外部来源获取的CSV文件,最好进行校验和清洗,确保数据完整性和准确性。可以使用Pyho中的数据清洗库,例如pandas,对数据进行预处理。
4.使用合适的库 在Python中,有很多库可以读写CSV文件,例如csv、pandas等。选择合适的库可以简化操作,提高效率。如果使用pandas)库,可以通过read_csv()和to_csv()函数读写CSV文件。
一、Express 介绍
Express是一个最小的,灵活的Node.js Web应用程序框架,它提供了一套强大的功能来开发Web和移动应用程序。 它有助于基于Node Web应用程序的快速开发。Express框架的核心功能是:
允许设立中间件响应HTTP请求定义了用于执行基于HTTP方法和URL不同动作的路由表允许动态渲染基于参数传递给模板HTML页面 二、安装Express
安装Express 框架全局使用NPM,以便它可以被用来使用Node终端创建Web应用程序。
$ npm install -g express-generator
上面的命令在本地node_modules目录保存安装,并创建一个目录express在node_modules里边。还有,应该使用express安装以下几个重要的模块:
body-parser :这是一个Node.js中间件处理JSON,Raw,文本和URL编码的表单数据multer :这是一个Node.js的中间件处理multipart/form-datacookie-parser : 解析Cookie头和填充req.cookies通过cookie名字键控对象 $ npm install body-parser --save $ npm install cookie-parser --save $ npm install multer --save
三、Express创建项目
一个非常基本的Express应用程序,它会启动服务器,并侦听端口3000等待连接。这个应用程序使用"Hello World! "回应!为请求网页。 对于所有其他路径,这将响应一个404表示未找到。
1、进入工作目录(自定义)
2、执行创建命令,创建一个名为hello的Express项目
express hello
表示安装成功
3、进入hello目录安装依赖包:
F:\hello> npm install
4、安装完成后,执行命令启动应用:
F:\hello>npm start
5、在浏览器中输入http://localhost:3000/
四、Express项目结构分析
1、bin:启动配置文件,在www 里修改运行端口号
2、node_modules:存放所有的项目依赖库,就像java存放架包
3、public:用于存放静态资源文件 图片,CSS,JAVASCRIPT文件..
4、routers:路由文件相当于springmvc中的Controller,ssh中的action
5、views:存放页面的地方
6、package.json:项目依赖配置及开发者信息。
7、app.js:应用核心配置文件,项目入口
五、app.js配置详解
app.js文件相当于项目启动的主入口文件,包含以下公共方法和服务器配置信息等
var createError = require('http-errors');//http错误处理模块 var express = require('express');//引入Express var path = require('path');//引入path var cookieParser = require('cookie-parser');//引入cookie处理对象 var logger = require('morgan');//引入日志模块 //引入路由目录中的index.
🔥博客主页: 小扳_-CSDN博客
❤感谢大家点赞👍收藏⭐评论✍ 文章目录
1.0 递归的说明
2.0 用递归来实现相关问题
2.1 递归 - 阶乘
2.2 递归 - 反向打印字符串
2.3 递归 - 二分查找
2.4 递归 - 冒泡排序
2.5 递归 - 冒泡排序2.0
2.6 递归 - 插入排序
2.7 递归 - 斐波那契
2.8 递归 - 兔子问题
2.9 递归 - 青蛙爬楼梯
1.0 递归的说明 递归就是在一个函数中调用自身。这样做可以让我们解决一些问题,比如计算斐波那契数列、阶乘等。
递归函数一般包括两部分:基本情况和递归情况。基本情况是指当问题变得很小,可以直接得到答案时,递归就可以停止了。递归情况是指在解决问题的过程中,需要不断地调用自身来解决更小规模的问题。
对于递归这个算法,简单的来说,方法自身调用自身的时候,需要有终止的条件,在运行过程中不断的趋向终止条件。还有递归总的来说有两个动作:第一个动作是递出,方法不断的在栈区中创建出来,直到达到了条件就会停止。第二个动作,达到条件停止了,就会回归,指方法在栈区中依次执行完后就销毁。
2.0 用递归来实现相关问题 以下的问题都较为简单,采取直接用代码来演示。
2.1 递归 - 阶乘 代码如下:
//阶乘 public static void main(String[] args) { System.out.println(fun(5)); } public static int fun(int n) { if (n == 1) { return 1; } return n * fun(n-1); } } 运行结果为:
目录 图片转PDF文件夹所有图片转为1个PDF文件夹指定图片转为1个PDF文件夹所有图片分别转为PDF举例 PDF转图片指定PDF转为图片文件夹所有PDF转为图片举例 图片转PDF 之前的一篇博客《Python合并拼接图片》,可对图片进行合并拼接
使用前需要安装PyMuPDF库,以下代码使用的PyMuPDF(1.23.6),以及自然排序库natsort(8.4.0)
文件夹所有图片转为1个PDF import fitz from glob import glob from natsort import natsorted def img2pdf_1(img_path, pdf_path, pdf_name): """ 将文件夹中所有格式图片全部转换为一个指定名称的pdf文件,并保存至指定文件夹 :param str img_path: 待转换图片所在文件夹 :param str pdf_path: 转换后PDF保存文件夹 :param str pdf_name: 转换后PDF文件名,不含扩展名 """ doc = fitz.open() filepath = [] for x in [r'\*.jpg', r'\*.png']: # 获取所有格式的图片 filepath.extend(glob(img_path + x)) # 将列表元素追加到列表中 for img in natsorted(filepath): # 读取图片,确保按文件名按自然排序 imgdoc = fitz.open(img) # 打开图片 pdfbytes = imgdoc.convert_to_pdf() # 使用图片创建单页的 PDF imgpdf = fitz.
目录 图片二维合并拼接(类似九宫格)图片纵向合并拼接举例18张图片合并为2张九宫格图片18张图片合并为2张纵向图片 使用前需要安装PIL库,以下代码使用的Pillow(10.1.0)
pip install pillow 图片二维合并拼接(类似九宫格) from PIL import Image def img_merge1(img_list, output_file, x, y, isresize=True): """ 合并图片列表中的图片,生成一个横向x个纵向y个的新图片,并指定保存名称 :param list img_list: 待合并的图片名称列表,文件名含路径 :param str output_file: 输出合并后的新图片,文件名含路径 :param int x: 合并后的新图片横向图片数 :param int y: 合并后的新图片纵向图片数 :param bool isresize: 是否统一每张图片的大小,默认True """ imgs = []; max_w, max_h = 0, 0 # 图片列表;图片最大宽,高 for f in img_list: img = Image.open(f); imgs.append(img) # 打开图片,并存入列表 w, h = img.size # 图片尺寸宽*高,元组 max_w = w if max_w < w else max_w max_h = h if max_h < h else max_h new_img = Image.
目录
写在前面 下载源码并解压
创建python项目
环境
过程
编译vnpy_ctp源码
验证可用性
写在前面 window系统中必须安装有Visual Studio ,后面源码安装时需要进行C++编译
下载源码并解压 GitHub - vnpy/vnpy_ctp: VeighNa框架的CTP交易接口
下载zip压缩包
解压
要在python中能执行,要有.pyd文件,解压后的文件夹内没有.pyd文件
创建python项目 新建一个python项目,项目在一个新的虚拟环境中执行。
环境 操作系统:window10 64位
开发工具:pycharm
python版本:python3.8.10
过程 编译vnpy_ctp源码 打开项目下方的terminal面板
cd 到解压后setup.py 所在文件夹 执行 python setup.py build 大概2到3分钟,编译完毕,在setup.py所在文件夹下多出一个build文件夹
在build下找到与操作系统和python版本对应的文件夹,以本文为例,操作系统是64位,那文件夹名称中就会有amd64,python版本3.8,文件夹名称中就会包含3.8,所以本文的文件夹名为lib.win-amd64-3.8
我们需要的是 build>lib.win-amd64-3.8>vnpy_ctp文件夹下的api文件夹,我们把api文件夹复制到项目目录下
验证可用性 创建Md调用的类和Td调用的类
import datetime,sys,os,time,pytz from api import ( TdApi, MdApi ) class CtpMdApi(MdApi): def __init__(self)->None: super().__init__() self.reqid:int = 0 self.connect_status: bool = False self.login_status: bool = False self.subscribed: set = set() self.
想在uniapp和vue3环境中使用echarts是一件相当前卫的事情,官方适配的还不是很好,echarts的使用插件写的是有些不太清晰的,这里我花费了一天的时间,终于将这个使用步骤搞清楚了,并且建了一个仓库,大家可以直接clone下来使用。先看一下pc端和小程序端的效果:
微信小程序和抖音小程序等都支持:
使用步骤如下 第一步:下载插件包
下载echarts插件包,并导入到项目中,然后使用插件中的组件创建容器,并导入数据就可以了。
echarts插件包地址:echarts - DCloud 插件市场
如果你是使用hbuilder写的,可以直接导入,如果你是vscode写的,就下载压缩包:
我这里将我下载好的zip包分享出来:lime-echart_0.8.1.zip - 蓝奏云
下载好解压然后将解压后的组件导入到项目的components下面:
并且将静态资源放到静态文件夹中:
第二步:安装echarts包
pnpm add echarts -or- npm install echarts 第三步:在页面中导入依赖并运行
然后在页面中导入这个LEchart这个组件:
将依赖按照不同的平台区分导入到页面组件中:下面是我的页面源代码
<template> <view> <view class="title">我的主页</view> <view> <LEchart class="echart" ref="chart" @finished="init"></LEchart> </view> </view> </template> <script setup> import LEchart from '@/components/l-echart/l-echart.vue' // lime-echart是一个demo的组件,用于测试组件 // import LEchart from '@/components/lime-echart/lime-echart.vue' import { onMounted, reactive, ref } from "vue" // nvue 不需要引入 // #ifdef VUE3 // #ifdef MP // 由于vue3 使用vite 不支持umd格式的包,小程序依然可以使用,但需要使用require const echarts = require('.
vue中使用高德地图marker标记点的setLabel,在不同层级下控制显示隐藏
设置点标注的文本标签
marker.setLabel({
offset: new AMap.Pixel(1, 0), //设置文本标注偏移量
content: '<div>' + name + '</div>', //设置文本标注内容
direction: 'top', //设置文本标注方位
});
监听地图层级变化
let _this = this;
var logMapChange = function () {
var mapZoom = _this.map.getZoom(); //获取当前地图级别
if (mapZoom < 15) {
_this.hideMarkerLabel(marker);
} else {
_this.showMarkerLabel(marker);
}
};
_this.map.on('zoomchange', logMapChange); //监听
标签显示
showMarkerLabel(marker) {
marker.setLabel({
offset: new AMap.Pixel(1, 0), //设置文本标注偏移量
content: '<div>' + marker._originOpts.title + '</div>', //设置文本标注内容
direction: 'top', //设置文本标注方位
前言 最近项目中需要用到高德地图搜索结果后的结果展示的可拉伸控件。
gaode.gif
而我看到这个效果图,觉得这个就是一个slidingpanel,但是翻阅了一些发现用google自带的bottomsheet实现更方便
什么是BottomSheet? Bottom Sheet是Design Support Library23.2 版本引入的一个类似于对话框的控件,可以暂且叫做底部弹出框吧。 Bottom Sheet中的内容默认是隐藏起来的,只显示很小一部分,可以通过在代码中设置其状态或者手势操作将其完全展开,或者完全隐藏,或者部分隐藏。对于Bottom Sheet的描述可以在官网查询:Material Design
怎么使用? 添加依赖
implemention 'com.android.support:design:25.3.1'布局文件 <?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/cl_chouti" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.amap.api.maps.MapView android:id="@+id/map_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center"> <ImageView android:id="@+id/mark" android:layout_width="30dp" android:layout_height="30dp" android:src="@drawable/poi_marker_pressed" /> <!--为了更好与定位之后的红点适配此imagview只是适配用没有意义--> <ImageView android:layout_width="30dp" android:layout_height="40dp" android:layout_below="@+id/mark" /> </RelativeLayout> </FrameLayout> <RelativeLayout android:id="@+id/bottom_sheet" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" app:behavior_hideable="true" app:behavior_peekHeight="160dp" app:layout_behavior="@string/bottom_sheet_behavior"> <include layout="@layout/layout_bottom_sheet" /> </RelativeLayout> </android.support.design.widget.CoordinatorLayout> layout_bottom_sheet.xml <?xml version="1.0" encoding="
基本符号 小写希腊字母 注:部分希腊字母在数学公式中常以变量形式出现,例如 ϵ \epsilon ϵ在数学中一般写法为 ε \varepsilon ε
符号语法符号语法符号语法 α \alpha α\alpha β \beta β\beta γ \gamma γ\gamma θ \theta θ\theta ε \varepsilon ε\varepsilon δ \delta δ\delta μ \mu μ\mu ν \nu ν\nu η \eta η\eta ζ \zeta ζ\zeta λ \lambda λ\lambda ψ \psi ψ\psi σ \sigma σ\sigma ξ \xi ξ\xi τ \tau τ\tau ϕ \phi ϕ\phi φ \varphi φ\varphi ρ \rho ρ\rho χ \chi χ\chi ω \omega ω\omega π \pi π\pi 大写希腊字母 大写希腊字母通常是小写希腊字母的LATEX语法第一个字母改为大写,见下表
STM32Cube +VSCode开发环境搭建 0.前言一、各种方式对比1.STM32CubeMX + CLion2.STM32CubeIDE + VSCode + STM32 VSCode Extension3.VSCode + EIDE插件 二、STM32CubeIDE + VSCode + STM32 VSCode Extension环境搭建1.需要安装的软件2.相关配置3.编译测试 三、总结 0.前言 工欲善其事,必先利其器。由于受够了eclipse风格的cubeide,直接用vscode打开工程目录又是一大堆波浪线,所以终于下定决心整整我的开发环境。
一、各种方式对比 stm32开发环境有很多方式,由于一些原因,这里就不使用keil+vscode方式进行介绍了,相关教程各大论坛也有不少,这里就介绍一下我踩坑的几种。环境搭建的宗旨是简单,尽量减少自己修改配置文件等繁琐步骤。
1.STM32CubeMX + CLion Clion作为比较现代化风格的IDE工具,并且支持像vscode风格的插件,用起来还是比较舒适的,不过缺点就是调试只能用openocd,这种方式需要加载芯片相关的cfg文件和寄存器映射表,所以搭建环境时还是比较麻烦的。笔者最终没有使用这种方式,因为所使用的STM32F103RCT6找不到对应的cfg文件和寄存器映射表文件,又懒得自己照着手册写。如果有想用这种方式的可以移步B站@Kevin_WWW大佬的相关视频。
注:这种方式最好使用官方能找得到芯片cfg文件的开发板,否则自己手动配置起来比较麻烦。
2.STM32CubeIDE + VSCode + STM32 VSCode Extension ST官方出了一个VSCode的相关插件,使用此插件可以直接打开对应的工程,支持编译下载和调试功能,本节内容主要也是以此方式介绍。
注:使用此方式前最好先在CubeIDE中查看自己的ST-Link是否满足要求,有些国产ST-Link过不了IDE检测,就无法正常烧录和调试。
3.VSCode + EIDE插件 由于笔者的两个ST-Link都无法过检测,又不想再花钱买新的,所以最终选择使用EIDE这种方式,使用起来甚至比第二种还要方便一点,相关教程可以移步同站@怠呆 大佬的《Windows VS Code + EIDE arm-none-eabi-gcc 开发STM32》。
二、STM32CubeIDE + VSCode + STM32 VSCode Extension环境搭建 1.需要安装的软件 ① STM32CubeIDE
② VSCode
③ cmake
④ STM32 VSCode Extension(vscode插件)
①和②的安装就不多介绍了,官网下载后安装就行。STM32CubeIDE建议安装在默认路径下,可以省去后续配置麻烦。更换了目录也行,笔者就是更换了目录后重新配置的,后续会介绍。
来源:OFD添加图片水印_ofdrw 水印-CSDN博客
通过http://t.csdn.cn/CzmeR这篇文章的引导,写出了一个ofd文件加图片水印的工具类,分享给大家参考。
1、引入ofdrw
<!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>provided</scope> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> <scope>provided</scope> </dependency> <!-- ofdrw --> <dependency> <groupId>org.ofdrw</groupId> <artifactId>ofdrw-full</artifactId> <version>1.6.4</version> </dependency> 2、工具类编写
import java.nio.file.Path; import ch.qos.logback.core.net.SyslogOutputStream; import com.itextpdf.text.BadElementException; import org.ofdrw.core.annotation.pageannot.AnnotType; import org.ofdrw.core.basicType.ST_Box; import org.ofdrw.font.FontName; import org.ofdrw.layout.OFDDoc; import org.ofdrw.layout.edit.Annotation; import org.ofdrw.layout.element.canvas.FontSetting; import org.ofdrw.reader.OFDReader; import com.itextpdf.text.Image; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; public class OfdUtil { /** * @param inputFile 输入路径 * @param outputFile 输出路径 * @param imgPath 图片路径 * @param dhzwz 加章位置: 1左上角、0中间、2右上角 */ public static String waterMark(String inputFile, String outputFile,String imgPath,String dhzwz) throws IOException, BadElementException { Path srcP = Paths.
大家经常会遇到手机信号弱的情况。
一般来说,我们会通过手机右上角的信号标识,来判断当前的信号强度。
但实际上,这个判断方式太过简陋。不仅精度不高,也不一定准确。
作为通信老司机,今天小枣君给大家介绍一些更专业的手机信号判断方法。同时,也给大家科普一些关于手机信号的基本常识。
首先,我告诉大家一些手机自带的信号查看方式。无需借助第三方App,就可以查看信号强度。
█ 苹果手机的查看方式
打开iPhone的拨号界面,在拨号键中输入 *3001#12345#* ,然后点击拨号按钮,就能查看手机的信号相关数据。
注意!不同版本的手机,这里的菜单内容会不一样。而且,要等一等,系统查询数据会需要一些时间。过一会儿,就会出来更多菜单。
点击【5G】下面的【NR Rach Attempt】,可以查看5G信号强度的数值(cell_rsrp,下图是-98):
点击【4G】下面的【Rach Attempt】,可以查看4G信号强度的数值(rsrp,下图是-87):
这些数值的单位是dBm。dBm是通过对数计算得出的,所以一般是负数值。(关于dBm的具体介绍,看这里:dB、dBm、dBw、dBi……到底有啥区别?)
注意,dBm的绝对值越小,表示信号质量越好。
对比参考如下:
在【RAT】的【Serving Cell Info】,还可以看到下面这些信息:
小枣君简单给大家解读几个比较重要的参数。
PLMN:运营商的公共陆地移动网编码。每个运营商都不一样。PLMN由MCC(移动国家码,3位)和MNC(移动网络码,2-3位)组成。46011是中国电信的4G/5G。
KCTCellMonitorBWPSupport:载波带宽自适应的支持类型。
Band Info:频段编号,图上的78是指n78。
5G频段编号(Sub-6频段)
Bandwidth:频率带宽,图上是20MHz。
CellID:小区编号。
Radio Access:无线接入类型。NR就是5G,LTE是4G。
NRARFCN:5G频点号。频段范围0-100GHz划出了总共3279165个栅格。这些栅格从0开始编号,一直编号到3279165。每个编号都代表着一个绝对的频域位置,这些编号就叫做NR-ARFCN。这个频点号有自己的计算公式,网上可查。
PCI:Physical Cell Identifier,物理小区标识。用于区分不同小区的无线信号。
TAC:Tracking Area Code,跟踪区代码。由运营商自行分配,主要起移动用户定位唯一标识作用。
█ 安卓手机的查看方式
再看看安卓。
不同品牌的安卓手机,查看信号强度的方式不太一样。
我们以小米(MIUI 14)为例,依次打开手机的【设置】-【我的设备】-【全部参数与信息】-【状态信息】-【SIM卡状态(SIM卡插槽1)】(或者插槽2),就可以查看到实时信号强度。如下图:
这个界面小米手机系统不让截屏,我只能拍照了。
信号强度是-93dBm。asu是Arbitrary Strength Unit,主观强度单位,可以看成是信号强度的相对值。
asu可以通过dBm得到,计算公式如下:
LTE和5G:asu=dBm+140
WCDMA和GSM: asu=(dBm+113)/2
网络类型是5G_SA,表示是5G独立组网(Standalone)。关于SA和NSA,可以看这里:5G的NSA和SA,到底啥意思?
█ 第三方App的查看方式
好了,以上是手机自带的查看方式。大家可以看到,查看的信息还是比较简单。
想要查看更详细的信息,怎么办?那就要借助第三方App软件了。
这类的软件比较多,我比较常用的是Cellular-Z。手机自带的应用商店应该都能下载到。不建议大家去网上找安装包,容易中毒。
Cellular-Z安装好之后,启动它,进入主界面:
可以看到,它功能比较全——除了手机两个卡槽的信号状态外,还能够看Wi-Fi和GNSS(卫星定位),以及手机自身完整信息。
卡槽信息的各个参数,小枣君刚才已经解读过,这里就不重复介绍了。有一个NR-FREQ,是手机目前具体的5G频率。
信号强度,显示了数值,也显示了动态图。前面说过,数值的绝对值越低,信号越好。
信号有好几个参数,我们分别说一下。(比较专业,不想看可以跳过)
RSRP:Reference Signal Receiving Power,参考信号接收功率。
我们主要看的就是这个参数。它是在某个Symbol(符号)内承载参考信号的所有RE(资源元素)上接收到的信号功率的平均值。范围在-44与-140之间,越大越好。
报错信息:
feign.FeignException$InternalServerError: [500] during [GET] to [http://USERS/users/2] [UserOpenfig#queryByUserId(Integer)]: [{"timestamp":"2023-11-09T11:39:16.890+00:00","status":500,"error":"Internal Server Error","path":"/users/2"}]
at feign.FeignException.serverErrorStatus(FeignException.java:250) ~[feign-core-11.10.jar:na]
at feign.FeignException.errorStatus(FeignException.java:197) ~[feign-core-11.10.jar:na]
at feign.FeignException.errorStatus(FeignException.java:185) ~[feign-core-11.10.jar:na]
at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:92) ~[feign-core-11.10.jar:na]
at feign.AsyncResponseHandler.handleResponse(AsyncResponseHandler.java:98) ~
openfeign请求代码:
@FeignClient("USERS") public interface UserOpenfig { @GetMapping("/users/{id}") public UserDto queryByUserId(@PathVariable("id") Integer id,String token); } @FeignClient("USERS") public interface UserOpenfig { @GetMapping("/users/{id}") public UserDto queryByUserId(@PathVariable("id") Integer id); } 接收代码
问题描述:
在使用openfeign传多个参数时,不加@RequestParam或者少写参数就会出现此类错误!
解决:
多参时参数加@RequestParam
前言 四次挥手相信大家都很熟悉了,为什么相较于TCP建立连接的三次握手需要多一次的原因网上也可以搜索到很多,本篇想要讲的主体和网上有点不一样,三次挥手在特定情况下也是可以的,相信大家搜到的原因说的都是特定情况下第二次和第三次挥手可以合并,那大家是否想过如果三次挥手是去掉第四次挥手呢?可以挥手成功吗?
一、首先,还是先讲一讲四次挥手的流程 图源TCP为什么需要三次握手和四次挥手?
第一次挥手:客户端发起断开连接请求,也就是发送一个FIN(finish)报文,并且报文中会指定一个序列号(序列号作用就是防止由于报文延迟到达而导致客户端已经超时重传了而出现服务端先后收到两次FIN报文,所以应该使用序列号唯一标记每一次发送的FIN报文,防止历史报文又被接收)。发送完成后客户端进入FIN_WAIT1状态,不再发送数据,等待来自服务端的确认
第二次挥手:服务端收到FIN报文后,就会把客户端的序列号值+1作为ACK报文的序列号,将确认收到ACK报文以及自身的随机序列号发送给客户端,发送完毕后服务端处于CLOSE_WAIT状态(服务端在收到客户端断开连接FIN报文后,并不会立即关闭连接)
第三次挥手:服务端数据全部传输完毕,服务端也申请断开连接,和客户端的第一次挥手一样,发送FIN报文,且指定一个序列号,发送完毕服务端进入LAST_ACK状态
第四次挥手:客户端收到FIN报文后,同样把服务端的序列号+1作为确认收到ACK报文的序列号值并发送,此时客户端进入TIME_WAIT状态(注意还没有进入关闭CLOSED状态,因为客户端发送的ACK报文可能在传输过程中丢失,所以需要等到服务端也确认收到才进入关闭状态,具体客户端等待时间大概需要略大于超时重传时间,超时重传时间过后没有收到服务端新的FIN报文就说明ACK报文被服务端接收到了),过了这段时间后客户端就可以进入CLOSED关闭状态,而服务端在接收到ACK报文之后也关闭连接,进入CLOSED状态。TCP连接成功断开!
二、为什么TCP断开连接不是像建立连接一样的三次握手?而是需要四次? 原因在于客户端请求断开连接后,但是服务端可能还存在没有传输完的数据,如果此时服务端就直接断开连接那势必会造成数据的丢失,TCP也就不可靠了。所以服务端需要等待所有数据发送完毕再请求断开,也就是服务端的ACK和FIN报文是分两次发送的。而TCP建立连接是不需要这个等待过程的,所以三次握手把服务端确认收到ACK报文和请求连接报文合并到了一起。
三、四次挥手可以变成三次吗? 既然上面提到之所以断开连接是挥手四次,是因为服务端在客户端请求断开连接后自身数据可能还没有发送完毕,如果此时断开连接就会造成数据丢失而变得不可靠。那如果发送完毕了呢?所以四次挥手是可以变成三次挥手的,条件就是服务端在收到客户端的请求断开连接FIN报文的时候已经不需要再发送数据了,那第二次挥手和第三次挥手就可以合并,从而实现三次挥手
以上其实网上可以找到很多相似的解释,笔者也在此指出。除此之外,笔者还有一点小思考。接下来才是我想写这篇文章的主要原因。
四、四次挥手想变成三次挥手可以是去掉第四次挥手吗? 三次挥手有两种情况:一种就是上面的把第二次挥手和第三次挥手合并为一次,另一种笔者想到的是去掉第四次挥手是否可行?这个问题的答案网上应该不多见,所以我试着来讲一下
去掉第四次挥手会造成什么呢?
第四次挥手是客户端发送响应服务端FIN报文的ACK报文,所以如果服务端不用确保收到ACK报文之后才关闭连接,那么就是服务端不知道客户端是否已经成功关闭连接了,服务端就先一步关闭了连接。设想这样一种情况,第三次挥手中服务端发送的FIN报文丢失了,由于我们设想的取消了第四次挥手的三次挥手的成立性,也就是服务端此时已经关闭了连接,而客户端(此时客户端是半关闭状态)由于收不到来自服务端的FIN报文,那又需要重新发送FIN报文请求断开连接,可此时服务端已经关闭连接了啊,那也就是说,服务端要想收到客户端的FIN报文,还需要重新三次握手建立连接之后才能接收到这个FIN报文,岂不是大大的资源浪费,建立TCP三次握手连接居然是为了断开连接?!!
这也就是第四次挥手存在的必然性。
所以,四次挥手的设计的是很合理的,每一步都存在着特定的意义和作用
效果
MD风格的底部弹窗,比自定义dialog或popupwindow使用更简单,功能也更强大。
其实细分来说,是BottomSheet、BottomSheetDialog、BottomSheetDialogFragment
代码 https://gitee.com/zhaoyanjun/bottomSheetDialogFragmentDemo
BottomSheet
与主界面同层级关系,可以事件触发,如果有设置显示高度的话,也可以拉出来,且不会影响主界面的交互。
XML
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white">
<LinearLayout
android:id="@+id/ll_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:behavior_peekHeight="80dp"
app:layout_behavior="@string/bottom_sheet_behavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent">
<TextView
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@android:color/holo_red_light"
android:gravity="center"
android:text="上拉解锁隐藏功能"
android:textColor="@color/white"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@android:color/holo_blue_light"
android:gravity="center"
android:text="a"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:text="b"
android:textSize="20sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@android:color/holo_green_light"
android:gravity="center"
android:text="c"
android:textSize="20sp" />
</LinearLayout>
</android.support.design.widget.CoordinatorLayout>
注意,
这里需要协调布局CoordinatorLayout包裹才行
app:behavior_peekHeight 显示高度,不显示的话设置为0即可
app:layout_behavior 标示这是一个bottom_sheet
以上3个条件都是必须的。
使用Vue框架,发现输入框<input>或者<el-input>的内容无法修改,也无法输入。
解决方案
首先,检查绑定方式,应该使用v-model,有时候会误用:value,导致无法修改。
其次,如果是绑定数组元素等复杂对象,可以在输入框添加@input="onInput()",然后在methods中添加方法:
onInput() {this.$forceUpdate();}, forceUpdate用来强制渲染,避免data中对象层次太深,Vue框架不自动渲染的情况。
journald参考文档:
journald.confhttps://www.freedesktop.org/software/systemd/man/latest/journald.conf.html
Amazonlinux2023系统默认不再安装rsyslog,因此在amazonlinux2中的诸多日志文件例如/var/log/message默认不可用。
AWS官方文档建议使用systemd的journalctl接口和相关包文件。
systemd-journald:
journald系统主要由三个系统日志服务组件组成:
守护程序:systemd-journald
配置文件:/etc/systemd/journald.conf
日志搜索程序:journalctl
配置文件主要配置: 配置文件路径:/etc/systemd/journald.conf
所有选项都在[Journal]部分配置
[Journal] #Storage=auto
Storage可选的值有:volatile、persistent、auto、none
volatile:日志数据文件存储在内存中,即/run/log/journal下
persistent:日志数据文件存储在磁盘中,即/var/log/journal下
auto:日志数据文件存储在磁盘中,即/var/log/journal下,但是这个目录必须存在
none:关闭存储,丢弃所有日志数据
[Journal] Compress=yes Seal=yes SplitMode=none
Compress:布尔值,默认启用,日志数据会被压缩
Seal:布尔值,数据加密
SplitMode:可选值有:uid和none,uid会将日志文件按用户uid进行切割,none则所有日志记录在一个文件中,但是非root用户无法访问自己的日志数据。
[Journal] SystemMaxUse=50M SystemMaxFileSize=50M SystemMaxFiles=1 RuntimeMaxUse=50M RuntimeMaxFileSize=50M RuntimeMaxFiles=1
SystemMaxUse:日志最多可以使用多少空间,默认为自己文件系统的10%
SystemMaxFileSize:日志文件最大大小
SystemMaxFiles:保留的最多文件数
RuntimeMaxUse=50M:存储在内存中的日志文件大小
RuntimeMaxFileSize=50M:存储在内存中最大文件大小
RuntimeMaxFiles=1:存储的最多文件数
journalctl主要用法 查看所有系统文件:journalctl 默认是分页显示的,可以正则匹配,输入? 内容进行匹配 只查看内核日志:journalctl -k 查看某个服务日志:journalctl -u mariadb -u 指定服务单元,systemd下面的所有service都可以指定
按时间查找日志: 几种写法:
journalctl --since "2023-11-01 00:00:00" --until "2023-11-03 00:00:00"
journalctl --since yesterday
journalctl --since 09:00
journalctl --since 09:00 --until "
:%s/yes//gn
软件工程一些图的画法 【一】数据库设计:ER图【1】ER图简介【2】实体之间的关系【3】ER图绘制常见问题【4】ER图转关系模式 【二】流程图【1】流程图的作用【2】流程图中使用的符号【3】三种循环的流程图画法【4】流程图的基本结构【5】流程图常用的形式 【一】数据库设计:ER图 【1】ER图简介 ER图,E就是实体,实体有一组属性;R是关系。找到系统中的实体以及实体关系就可以绘制出ER图。
矩形的是实体,椭圆是属性,实体和实体之间的关系用菱形,关系也有属性。
例如:
学生有【学号、姓名】等诸多属性,是一个实体。
课程有【课程名、学分】等属性,也是一个实体。
而学生有选修课程的关系,所以这两个实体之间有个选课关系。而且选课还有成绩,所以在选修关系上有一个属性【成绩】,如果系统需要,也可以记录选修的时间等属性信息。
【2】实体之间的关系 ER图中识别出实体后,找到实体之间的关系很重要。而关系可能是一对一(1:1)、一对多(1:n)、多对多(m:n),关系用菱形表示,而关系的类型在菱形的两条与实体的连接线上标注,判断两个实体的关系是,先让实体A假设为1,看它能对应实体B的个数,然后反过来,假设实体B为1个,看实体A对应的个数,就可以得到实体对应关系。
(1)1个学生可关注多个商品,而1个商品可被多个学生关注,所以学生和商品的关系是多对多。
(2)1个学生属于1个班级,而1个班级可以有多个学生,所以班级和学生的关系是一对多。
(3)1个学生拥有1张饭卡,而1张饭卡只属于1个学生,所以学生和饭卡的关系是一对一。
【3】ER图绘制常见问题 (1)反例1:区分功能和关系
例如,管理员可以管理用户,但是如果系统不记录哪个管理员可以管理哪些用户,那么就无需再ER图上绘制该关系。只有需要再数据库保存的关系,才需要再ER图上保存。
(2)反例2:区分程序功能和数据库数据
挂号排队信息,我个人挂号排队一般不用保存到数据库,所以无需在ER图上表示。另外,如果要显示排队信息,应当是给每个用户一个id序号,程序实现排队,而不是数据库去记录这个排队信息。
【4】ER图转关系模式 所有的实体应当转为一张表。所以上面的班级、学生、课程、教师都是一张表。
班级表包含字段:班级号、班级名、专业、人数,主键:班级号
学生表包含字段:学号、姓名、性别、年龄,主键:学生号
课程表包含字段:课程号、课程名、课时、学分,主键:课程号
教师表包含字段:编号、姓名、职称、年龄、性别,主键:编号
根据关系是1:1、1:n、m:n转成表
(1)对于1:1的,可以把关系保存到任何一个实体表中
(2)对于1:n的,可以把关系保存到n的那个实体里,例如图中的班级和学生是1对多,那么可以在学生表中增加一个班级id的字段,说明该学生是哪个班级的
学生表包含字段:学号、姓名、性别、年龄、班级id,主键:学生号
(3)对于多对多的关系m:n的,关系保存到新表中
例如,学生和课程是多对多的关系,那么把这两个表的主键拿出来,加上关系属性,组成一个表
学生成绩表:学号、课程号、成绩,主键:学号、课程号
【二】流程图 【1】流程图的作用 流程图可以简单地描述一个过程,是对过程、算法、流程的一种图像表示,在技术设计、交流及商业简报等领域有广泛的应用。流程图可以分为:数据流程图、作业流程图。
流程图的优点:
(1)采用简单规范的符号,画法简单
(2)结构清晰,逻辑性强
(3)便于描述,容易理解
【2】流程图中使用的符号 流程图是用图的形式把一个过程的步骤表示出来,使用图形表示算法的思路是一种极好的方法。流程图由包含具有确定含义的符号、简单的说明性文字和各种连线。
通用的绘制流程图形态和程序的习惯性做法是:
(1)开始用六角菱形或圆角矩形或椭圆
(2)矩形方框表示具体活动过程
(3)菱形框表示决策、审核、判断
(4)结束终止用椭圆
(5)平行四边形表示输入输出
(6)箭头代表工作流方向
另外还规定,流程线是从下往上或从右往左时,必须带箭头;除此之外,都可以不画箭头;流程线的走向默认都是从上向下或者从左往右。符号内的说明文字尽可能简明,通常按从左往右和从上往下的方式书写。并与流向无关。如果说明文字较多,符号内写不完,可以使用注解符。如果注解符干扰或影响到图形的流程,应在另外一页正文上注明引用符号
【3】三种循环的流程图画法 (1)for循环
for循环形式: for(表达式1;表达式2;表达式3)
(2)while循环
while(判断条件){ 执行语句; } (3)do-while循环
do{ 执行语句; }while(条件判断) 【4】流程图的基本结构 有顺序结构、分支结构(又称选择结构)、循环结构三种
【5】流程图常用的形式 流程图常用的形式有两种
(1)上下流程图
上线流程图是最常见的一种流程图,它仅表示上一步和下一步的顺序关系
删除重复数据,只保留一条
1.使用开窗函数进行数据去重
Delete T From (Select Row_Number() Over(Partition By Fdate,col1,col2 order By Fdate) As RowNumber,* From [dbo].[table_nam] )T Where T.RowNumber > 1
项目中需要用到下面的几个类
但项目打包时,出现“程序包com.sun.image.codec.jpeg”不存在的问题
解决方法一:
setting - maven - runner - Delegate IDE build/run action to Maven(打钩即可)
解决方法二:
在pom.xml文件中,添加以下代码:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> <encoding>${project.build.sourceEncoding}</encoding> <compilerArguments> <verbose/> <bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar</bootclasspath> </compilerArguments> </configuration> </plugin>
活动地址:https://activity.csdn.net/creatActivity?id=10593
参与奖获得奖名单
用户昵称博文链接秋说【约会云栖】从初中至大学,我见证了科技变革的历程。-CSDN博客Freedom35682019年云栖大会,我的技术元年-CSDN博客码农研究僧云栖大会:探索科技前沿,见证变革历程-CSDN博客知孤云出岫我和云栖有个约会-CSDN博客知识浅谈携手云栖,共望未来-CSDN博客人间打气筒(Ada)云栖大会所感所想-CSDN博客想你依然心痛https://blog.csdn.net/u014727709/article/details/134133051计算机魔术师【我与云栖大会的缘分】以引领云计算创新为宗旨,以坚持开放为姿态-CSDN博客魔法自动机我和云栖有个约会-CSDN博客cooldream2009关注云栖大会的感受:从工业大脑到全面AI时代的进化-CSDN博客三掌柜666https://blog.csdn.net/CC1991_/article/details/134143379云边散步对未来云栖大会的期待与建议-CSDN博客职业潜水人【云栖大会】参会有感-CSDN博客黑夜开发者约会杭州云栖2023:为了无法计算的价值一起努力-CSDN博客指剑我和云栖有个约会-CSDN博客编程轨迹_与云栖的浪漫邂逅:记一段寻找云端之美的旅程-CSDN博客库库的里昂2023杭州.云栖大会:计算,为了无法计算的价值-CSDN博客knighthood20012023年云栖大会来啦!!(2022年就已经深受震撼)-CSDN博客Open-AI《与云栖共筑创新未来》-CSDN博客抱抱宝2023我和云栖有个约会-CSDN博客全栈若城我和云栖有个约会 - 仿佛是一个穿越的体验-CSDN博客熬夜磕代码丶万物皆可“云” 从杭州云栖大会看数智生活的未来_云栖大会 思考-CSDN博客毕加锁我和云栖有个约会-CSDN博客auspicious航我和云栖大会有个约会-CSDN博客GA666666我的云栖大会之旅:见证云计算创新的15年-CSDN博客度假的小鱼2023云栖大会:揭示未来科技的璀璨星辰-CSDN博客赵四司机【云栖大会】我与“云栖”共成长-CSDN博客三掌柜666我和“云栖大会”的双向奔赴-CSDN博客王二蛋!我和云栖有个约会-CSDN博客中杯可乐多加冰2023杭州·云栖大会:我在云栖看数智中国-CSDN博客进击的雷神悟道云端,探索测试新境-CSDN博客Helloorld_11阿里云领取云服务器-CSDN博客N-A云栖大会十五年:开放创新,未来愿景-CSDN博客烟雨江南......https://blog.csdn.net/mabide1234/article/details/134185686syst1m'“云栖~” 是你吗?-CSDN博客 恭喜以上获奖用户,后面将会有专属人员联系您搜集地址,还请关注您的私信通知
注:本次上榜博主只有创作和主题相关的博文方可,由于上榜文章质量普遍偏低,「录用奖」没有入围者。