Visual Studio Code +PHP开发 推荐插件

1、PHP Intelephense: 超好用 php 智能代码提示器,支付代码提示、查找定义、类搜索等功能,非常强大 2、PHP 接口注释插件:安装好后可以使用 “/**” 快捷键 + Tab 自动生成接口和文档注释,用于函数,类的快速注释 更多配置可以参考插件说明 3、PHP debug插件 调试器,此插件需要安装 php-xdebug 并配置,之后才可正常使用 4、php intellisense,php 代码自动完成插件; 5、PHP Namespace Resolver 命名空间 的快速引入, 选中类,按ctrl+alt+I 6、Code Spell Checker 单词拼写检查插件,只要你的单词拼写错误就会在错误单词下有个波浪线提示,避免错误的命名非常好用。 7、code runner 可以直接在编辑器中运行代码,查看结果,非常方便,一键运行

LINUX添加用户

背景 好吧,我再重新温故一下如何再linux上添加用户。 添加用户 你必须有root权限。 来个例子 useradd -d /home/username -m username -s /bin/bash -g groupName 1 ‘-d /home/username’:指定创建用户登陆时的目录,如果不存在会递归自动创建的。 ‘-m username’:创建用户的用户名,用以登陆系统的账号名称 ‘-s /bin/bash’:为创建的用户指定登陆时默认的shell ‘-g groupName’:为创建的用户指定属组,该组名必须真实存在 具体知识点 Linux 用户和用户组管理 Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统。 用户的账号一方面可以帮助系统管理员对使用系统的用户进行跟踪,并控制他们对系统资源的访问;另一方面也可以帮助用户组织文件,并为用户提供安全性保护。 每个用户账号都拥有一个唯一的用户名和各自的口令。 用户在登录时键入正确的用户名和口令后,就能够进入系统和自己的主目录。 实现用户账号的管理,要完成的工作主要有如下几个方面: 用户账号的添加、删除与修改。 用户口令的管理。 用户组的管理。 一、Linux系统用户账号的管理 用户账号的管理工作主要涉及到用户账号的添加、修改和删除。 添加用户账号就是在系统中创建一个新账号,然后为新账号分配用户号、用户组、主目录和登录Shell等资源。刚添加的账号是被锁定的,无法使用。 1、添加新的用户账号使用useradd命令,其语法如下: useradd 选项 用户名 1 参数说明: 选项: -c comment 指定一段注释性描述。 -d 目录 指定用户主目录,如果此目录不存在,则同时使用-m选项,可以创建主目录。 -g 用户组 指定用户所属的用户组。 -G 用户组,用户组 指定用户所属的附加组。 -s Shell文件 指定用户的登录Shell。 -u 用户号 指定用户的用户号,如果同时有-o选项,则可以重复使用其他用户的标识号。 用户名: 指定新账号的登录名。 实例1 useradd –d /home/sam -m sam

hbase股票数据分析

本文是西南交大研究生课程《大数据智慧管理机制》的课程设计,做个笔记马克一下。 课程设计意义与目的 Hbase是非关系型大数据管理技术,基于hadoop的NoSQL,从而具有面向大数据5V特点的存储优势,具有强大的吞吐能力和扩展性。传统的关系型数据库涉及多表联结查询及Group by或Order by等操作,在分布式系统高并发环境下,当数据量达到几千万甚至至几亿级别时,一个SQL查询会达到分钟级别以上,效率低下;而HBase采用的是Key/Value的列式存储方式(数据即索引),即使数据海量,查询效率依然能满足通常的要求。此外,由于基于分布式文件系统,可以将数据分片放在不同的服务器上,进一步增加高并发能力,减少了负载压力。 由于HBase简单的存储方式,它不支持Group by, Order by等操作, 不擅长数据分析,只能借助MapReduce或协处理器( Coprocessor)来实现少量复杂查询。因此,HBase等NoSQL数据库适合千万以上数据量并且需要高并发的应用环境。因此此次的hbase实践有助于我们更深入的学习大数据的处理。 2. 课程设计内容 2.1需求分析及源数据集情况 本设计基于Hbase实现一个股票管理系统,应用NoSQL技术完成大数据的管理和查询任务。应用需求主要有股票记录的数据库维护管理、记录查询、数据统计分析。在记录维护管理模块,设计UI界面,添加、修改和删除数据;在查询和统计分析模块,实现简单的条件查询、组合条件查询、统计分析等任务。 实践项目使用了股票数据集作为源数据,该数据是关于20家上市公司的1991年到2016年的股票信息,数据量约为120000条记录。相关属性如:股票代码,股票简称,日期,前收盘价,开盘价,最高价,最低价,收盘价,成交量,成交金额,涨跌,涨跌幅,均价,换手率,总市值。其中股票代码和股票简称为股票的基本信息,其余为可计算的统计信息。 2.2 逻辑和物理设计,模型展示。 2.2.1系统架构 本设计的后端由数据库Hbase以及它所基于的分布式文件系统HDFS构成,客户端通过web和java服务器与后端通信,Hbase的java api实现数据的增删改查后,将数据返回给前端。 2.2.2 Hbasse数据库模型设计 Hbase与传统的关系型数据库不同,它是一个稀疏的、多维度的、排序的映射表。每张表都有一个列族集合, HBase通过列族的概念来组织数据 的物理存储。每行都有一个可排序的主键(主键之一的行键按字典顺序排列)和任意多个列。行和列所决定的单元中存储数据,数据类型是字节数组byte[]。由于HBase的无模式特性,同一张表里的每一行数据都可以有截然不向的列。HBase中所有数据库在更新时都有一个时间印标记,每一次更新都是一个新的版本,HBase会保留一定数量的版本,客户端可以选择获取距离某个时间点最近的版本单元的值,或者一次获取所有版本单元的值。根据HBase上述特点设计本实践项目中的股票记录表,如表1所示。该表分为两个列族,列族StockInfo包含股票基本信息,列族Statistic包含股票统计信息。 表1 股票记录表 Rowkey 列族(StackInfo) 列族(Statistic) Code Name GMV RANGE 03_000001.SZ_20071228 000001.SZ 平安银行 2376508379 50 03_000002.SZ_20071228 000002.SZ 万科A 601376594.4 73.3333 …… 13_000004.SZ_20071228 000004.SZ 中国宝安 2832630790 11.1484 13_000005.SZ_20071228 000005.SZ 深物业A 2935635546 12.7659 Hbase中的数据按照rowkey进行排序,region的配置在建表的时候设定。本设计有两个列族,因此一个region有两个store,store以Hfile的形式存储在HDFS上。 2.2.3行键设计 Hbase行键的设计很重要,一条数据的唯一标识就是 rowkey,这条数据存储于哪个分区,取决于 rowkey 处于哪个一个预分区的区间内,设计 rowkey 的主要目的,就是让数据均匀的分布于所有的 region 中,在一定程度上防止数据倾斜。 本设计的rowkey设计方案:将 Rowkey 的高位作为散列字段,由股票的年月进行哈希取余,中位为股票代码,低位放时间字段,例如:

蓝桥杯模块学习4——数码管(深夜学习——单片机)

目录 一、硬件部分: 1、573锁存器: 2、共阳极数码管:​编辑 3、总体思路: 二、静态数码管: 1、代码思路: 2、参考代码: 3、参考代码(模块化): 三、动态数码管: 1、代码思路: 2、参考代码: (1)宏定义函数: (2)主函数: 四、动态数码管(优化): 五、动态数码管(中断显示):(建议学习过定时器后再来看以下代码) 一、硬件部分: 1、573锁存器: 如果还不懂可以参考之前的点亮LED灯的文章 蓝桥杯模块学习2——LED灯(深夜学习——单片机)_佛科院深夜学习的博客-CSDN博客https://blog.csdn.net/weixin_63568691/article/details/128431461 2、共阳极数码管: 图1 (1)其实可以把数码管可以看作多个LED灯组成的电路,每个数字由8个LED组成 (2)什么叫共阳极? 可以理解为LED灯的一端接了VCC,只需要在另一端输入低电平就能将他点亮 (3)封装好的共阳极数码管1-F对应的十六进制数: //定义一个数组存放从0-f对应的16进制数 //code 关键字的作用是我定义的数据要存放到ROM区,写入后不可以被改变 //输入16为分隔符号 u8 code transistor_positive[]= { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e, 0xfd }; //带小数点 u8 code transistor_positive_point[]= { 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78, 0x00,0x10,0x08,0x03,0x46,0x21,0x06,0x0e }; 3、总体思路: 图2 (1)由图1可知,我们先通过右边com口(位选)选择需要亮的数码管,再通过左边八个口(段选)确定要选择的数字 (2)由图2可知,单片机通过两个573锁存器控制数码管的位选和段选,只需要按照之前的方法对锁存器进行选择再输入数据即可 二、静态数码管: 实现功能:8个数码管分别单独逐次显示1-8,然后所有数码管同时逐次显示0-F 1、代码思路: 由上述硬件电路可知只需要选择相应的锁存器和输入相应的数据就行了 2、参考代码: // 使用程序前,将J13调整为IO模式(2-3脚短接) #include "reg52.h" #include "Public.h" //定义一个数组存放从1-f对应的16进制数 //code 关键字的作用是我定义的数据要存放到ROM区,写入后不可以被改变 u8 code transistor_positive[]= { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e }; //带小数点 u8 code transistor_positive_point[]= { 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78, 0x00,0x10,0x08,0x03,0x46,0x21,0x06,0x0e }; void HC138_Y(u8 num); void Close_All(void); void main(void) // 主函数 { u8 i; while(1) { Close_All(); //8个数码管分别单独逐次显示1-8 for(i=1;i<=8;i++) { //改变数据 HC138_Y(7); P0 = transistor_positive[i]; //改变显示位置 HC138_Y(6); P0 = 0x01<<(i-1); Delay_1ms(500); } //数码管同时逐次显示0-F for(i=0;i<16;i++) { //改变数据 HC138_Y(7); P0 = transistor_positive[i]; //改变显示位置 HC138_Y(6); P0 = 0xff; Delay_1ms(500); } } } /* 输入变量:4-7 输出变量:无 功能:操作138译码器,4-7分别对应Y4-Y7,其余都会使译码器不起作用 */ void HC138_Y(u8 num) { switch(num) { case 4:P2 = (P2 & 0x1f) | 0x80;break; case 5:P2 = (P2 & 0x1f) | 0xA0;break; case 6:P2 = (P2 & 0x1f) | 0xC0;break; case 7:P2 = (P2 & 0x1f) | 0xE0;break; default:P2 = (P2 & 0x1f) | 0x00; } } /* 输入变量:无 输出变量:无 功能:关闭蜂鸣器和继电器 */ void Close_All(void) { P2 = (P2 & 0x1f) | 0xA0; P0 = 0x00; } 3、参考代码(模块化): // 使用程序前,将J13调整为IO模式(2-3脚短接) #include "

【HBase——陌陌海量存储案例】2. HBase表结构设计(中)

前言 本文是陌陌海量存储案例——HBase表结构设计(中),介绍ROWKEY设计原则、项目初始化。 4.5 ROWKEY设计原则 4.5.1 HBase官方的设计原则 避免使用递增行键/时序数据 如果ROWKEY设计的都是按照顺序递增(例如:时间戳),这样会有很多的数据写入时,负载都在一台机器上。我们尽量应当将写入大压力均衡到各个RegionServer 避免ROWKEY和列的长度过大 在HBase中,要访问一个Cell(单元格),需要有ROWKEY、列蔟、列名,如果ROWKEY、列名太大,就会占用较大内存空间。所以ROWKEY和列的长度应该尽量短小ROWKEY的最大长度是64KB,建议越短越好 使用long等类型比String类型更省空间 long类型为8个字节,8个字节可以保存非常大的无符号整数,例如:18446744073709551615。如果是字符串,是按照一个字节一个字符方式保存,需要快3倍的字节数存储。 ROWKEY唯一性 设计ROWKEY时,必须保证RowKey的唯一性由于在HBase中数据存储是Key-Value形式,若向HBase中同一张表插入相同RowKey的数据,则原先存在的数据会被新的数据覆盖。 4.5.2 避免数据热点 热点是指大量的客户端(client)直接访问集群的一个或者几个节点(可能是读、也可能是写)大量地访问量可能会使得某个服务器节点超出承受能力,导致整个RegionServer的性能下降,其他的Region也会受影响 预分区 默认情况,一个HBase的表只有一个Region,被托管在一个RegionServer中 每个Region有两个重要的属性:Start Key、End Key,表示这个Region维护的ROWKEY范围如果只有一个Region,那么Start Key、End Key都是空的,没有边界。所有的数据都会放在这个Region中,但当数据越来越大时,会将Region分裂,取一个Mid Key来分裂成两个Region预分区个数 = 节点的倍数。默认Region的大小为10G,假设我们预估1年下来的大小为10T,则10000G / 10G = 1000个Region,所以,我们可以预设为1000个Region,这样,1000个Region将均衡地分布在各个节点上 ROWKEY避免热点设计 反转策略 如果设计出的ROWKEY在数据分布上不均匀,但ROWKEY尾部的数据却呈现出了良好的随机性,可以考虑将ROWKEY的翻转,或者直接将尾部的bytes提前到ROWKEY的开头。反转策略可以使ROWKEY随机分布,但是牺牲了ROWKEY的有序性缺点:利于Get操作,但不利于Scan操作,因为数据在原ROWKEY上的自然顺序已经被打乱 加盐策略 Salting(加盐)的原理是在原ROWKEY的前面添加固定长度的随机数,也就是给ROWKEY分配一个随机前缀使它和之间的ROWKEY的开头不同随机数能保障数据在所有Regions间的负载均衡缺点:因为添加的是随机数,基于原ROWKEY查询时无法知道随机数是什么,那样在查询的时候就需要去各个可能的Regions中查找,加盐对比读取是无力的 哈希策略 基于 ROWKEY的完整或部分数据进行 Hash,而后将Hashing后的值完整替换或部分替换原ROWKEY的前缀部分这里说的 hash 包含 MD5、sha1、sha256 或 sha512 等算法缺点:Hashing 也不利于 Scan,因为打乱了原RowKey的自然顺序 4.5.3 陌陌打招呼数据预分区 预分区 在HBase中,可以通过指定start key、end key来进行分区,还可以直接指定Region的数量,指定分区的策略。 指定 start key、end key来分区 hbase> create 'ns1:t1', 'f1', SPLITS => ['10', '20', '30', '40'] hbase> create 't1', 'f1', SPLITS => ['10', '20', '30', '40'] hbase> create 't1', 'f1', SPLITS_FILE => 'splits.

MySQL登录报错1045解决办法-1045-Access denied for user ‘root‘@‘‘(using password:YES)

此报错的原因则是没有开通权限 解决方案: 1、打开cmd命令面板 2、输入mysql -u root -p,之后输入密码(数据库root账户的密码) 3、开通权限 全部开放 GRANT ALL PRIVILEGES ON . TO ‘root’@‘%’ IDENTIFIED BY ‘password’ WITH GRANT OPTION; 指定ip开放 GRANT ALL PRIVILEGES ON . TO ‘root’@‘192.168.12.1’ IDENTIFIED BY ‘password’ WITH GRANT OPTION; 4、刷新权限flush privileges; 5、重启MySQLnet stop mysql,net start mysql

配置普通linux平台用户访问k8s集群

生产环境对于业务的稳定性要求是相当高的,为了防止误操作,通常是通过不同的账号与权限来进行限制的。对于k8s集群而言,部署的时候通常是以linux root用户的身份进行部署的,k8s的安全机制是,认证、鉴权、准入控制;意味着除root用户外,其他普通用户不具备请求k8s集群资源的权限。普通用户访问k8s资源需要做认证与授权操作。 认证: 1、查看 认证之前首先查看普通用户(自定义的普通用户zs)访问k8s集群报什么错 [root@master01 ~]# su - zs [zs@master01 ~]$ kubectl get nodes 报错提示:连接到本机8080端口的服务被拒绝了,是否指明了正确的主机或者端口。即不能与apiserver交互。 2、创建证书(切回root用户) [root@master01 ~]# cd /etc/kubernetes/pki/ [root@master01 pki]# openssl genrsa -out zs.key 2048 [root@master01 pki]# openssl req -new -key zs.key -out zs.csr -subj "/CN=zs/O=zs" [root@master01 pki]# openssl x509 -req -in zs.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out zs.crt -days 3650 3、查看、设置集群、用户、上下文信息 查看集群信息、因为我之前做高可用,所以监听的端口是16443而不是6443,正常情况下默认是6443。 [zs@master01 ~]$ kubectl cluster-info 设置名为kubernetes集群 [root@master01 pki]# kubectl config set-cluster kubernetes --embed-certs=true --certificate-authority=/etc/kubernetes/pki/ca.

OCCT里的Mesh网格计算流程

Open CasCade Technology简称OCCT, 在OCCT中有2种网格转换器: VRML转换器 作用:将Open CASCADE Shape形状翻译成VRML 1.0文件(虚拟现实建模语言) Open CASCADE Shape形状可以被翻译成两种表现形式:阴影或线框。阴影表示法将形状表现为由网格算法计算的三角形集合,而线框表示法将形状表现为曲线集合。STL转换器 作用:将Open CASCADE Shape形状翻译成STL文件。 STL(STtereoLithography)格式被广泛用于快速原型设计。 1 Mesh网格的计算流程 图(1) Mesh网格的计算流程 图(1)所示,Mesh网格的计算流程是:创建数据模型 --> 离散化边缘、2D/3D曲线(对Edge进行离散化) --> 修复离散模型 --> 预处理 --> 对Face进行离散化 --> 后处理 --> 得到网格。 1.1 创建数据模型 【Create Model Data Structure】 将源TopoDS_Shape分解为Face和Edge。为每个实体创建一个反射。 1.2 对Edge进行离散化 【Discretize Edges 3D &2D Curves】 将模型的边缘Edge离散为一组3D曲线或2D曲线,形成一个连贯的骨架,为面的网格剖分打基础。 1.3 修复离散模型 【Heal Discrete Model】 分析并修复离散模型,使其满足预处理的标准。比如,对于自相交的,可以通过引入粗略离散的边来解决;如果无法修复,则拒绝该模型。 1.4 预处理离散模型 【Preprocess Discrete Model】 对模型面Face进行迭代,检查现有三角形的一致性,若不一致,则清理相关的拓扑面和相邻的边。 1.5 对Face进行离散化 【Discretize Faces】 使用二维离散数据对特定的Face进行网格生成,将数据存储到TopoDS_Face中。 1.6 后处理离散模型 【Postprocess Discrete Model】

ubuntu20.04 安装nvidia驱动

命令nvidia-smi 使用nvidia-smi,若输出结果显示命令未找到,说明没下载驱动。 查看推荐的nvidia驱动版本 ubuntu-drivers devices 后面带有recommended的就是推荐的版本(看一些网上资料好像说是会推荐比较高版本的) 可以在soft&updatt里面找到additional drivers,那里可以直接下载驱动。但是,我系统推荐的是nvidia-driver-525-open,不知道为啥后面老是失败(可能和open有关..?)。我后面发现安装nvidia-driver-525我就成功了 报错历史 1.驱动失效 NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver. 参考了博客:NVIDIA驱动失效简单解决方案:NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver._AI 菌的博客-CSDN博客 我使用nvcc -V查看了输出正常,再输入 ls /usr/src | grep nvidia 来检查驱动版本,使用命令 sudo apt-get install dkms sudo dkms install -m nvidia -v 525 重新安装了一下,但是显示的是,该版本的驱动已经安装了。 2.重启后,报错:no devices were found 反复安装推荐的版本,无果。重启了一下,发现报错内容变了,变成了no devices were found。查找了很多资料,无果。无奈之下,我换了nvidia的版本,从nvidia-525-driver-open换成了nidia-driver-525,然后重启,就成功了?! 怎么说呢,刚开始很多都不懂,小白初试,走了很多弯路,但在过程中学到了很多知识,最后正确额输出了真的很开心了,过程中参考了很多博客和其它资料,有一些真的受益匪浅,感谢!

GPU资源排队脚本,支持多个GPU资源(可指定GPU或指定排队运行次数)

由于GPU资源在大部分时间会被较多人使用,而部分时间可能较少人或者没有人使用,这样就会在一定程度上造成GPU资源的浪费,因此出于这个目的写了GPU资源的排队脚本,这里主要是针对多个GPU资源来实现的: 参考:https://blog.csdn.net/leviopku/article/details/102958166 代码如下: 下面展示一些。 import os import sys import time cmd = 'python xxx.py(py文件名)' def get_info(): gpu_memory_list = [] gpu_status = os.popen('nvidia-smi | grep %').readlines() for list_ in gpu_status: list_ = list_.split('|') gpu_memory = int(list_[2].split('/')[0].split('M')[0].strip()) gpu_memory_list.append(gpu_memory) # 主要是针对memory操作,如果对power需要操作的话同理 # gpu_power = int(list_[1].split(' ')[-1].split('/')[0].split('W')[0].strip()) return gpu_memory_list def setup_python(interval=1): gpu_memory_list = get_info() i = 0 while(i!=7): if gpu_memory_list[i] <= 2000: # 设置条件,满足则运行python程序 if i==0 or i==5 or i==6: # 指定特定的GPU print('\n'+cmd) os.

Jupyter Notebook 更改默认存储路径、更改默认浏览器、添加虚拟环境的kernel

文章目录 1.更改默认存储路径1.1 修改配置文件1.2 修改快捷方式 2.更改默认浏览器3.添加虚拟环境的kernel 1.更改默认存储路径 1.1 修改配置文件 Jupyter Notebook 的默认存储路径是 C:\Users\用户名,接下来我们修改 Jupyter Notebook 的默认存储路径。 打开 Anaconda Prompt,执行如下命令: jupyter notebook --generate-config 该命令执行完成后,会在 C:\Users\用户名\.jupyter 目录下生成一个名叫 jupyter_notebook_config.py 的配置文件。 使用记事本或Notepad++等编辑软件打开配置文件,然后使用快捷键 ctrl + f 搜索 c.NotebookApp.notebook_dir 配置项,默认为: # c.NotebookApp.notebook_dir = '' 删除前面的空格和#号,添加想要更换的目录,内容修改如下: c.NotebookApp.notebook_dir = 'E:\dev\JupyterNotebook' 经过这步操作后,如果在 Anaconda Prompt 中输入 jupyter notebook 命令,则可以正确跳转到修改后的目录。 1.2 修改快捷方式 经过上一步操作后,如果在开始菜单中点击 Jupyter Notebook,此时无法正确跳转到修改后的目录。 在开始菜单中右键 Jupyter Notebook,打开文件位置: 右键快捷方式,点击属性: 删除 "%USERPROFILE%/",点击应用,点击确定: 至此,无论是通过快捷方式还是命令行进入 Jupyter Notebook,都能正确跳转到修改后的目录。 2.更改默认浏览器 使用记事本或Notepad++等编辑软件打开 jupyter_notebook_config.py 配置文件,然后使用快捷键 ctrl + f 搜索 c.

HTML语法标签大全

HTML语法标签大全 1.语法标签通常由<,>,/组成,通常是双标签,一般形式为<开始标签>包裹内容</结束标签>, 也有但标签,一般形式为<>,而且不能包裹内容 2.标签与标签之间的关系👇: 1.嵌套关系 2.并列关系 <head> <head></head> <title></title> <body></body> <head> 一.标题标签 <h1>1级标题</h1> 注意:1. 1~6级标签,重要程度依次递减 <h2>2级标题</h2> 特点:1.文字自动加粗 <h3>3级标题</h3> 2.自动换行 <h4>4级标题</h4> <h5>5级标题</h5> 一般只会用到h1-h3 <h6>6级标题</h6> 1.段落标签 1.用于分段显示内容(段落) 2.代码:<p> </p> 3.特点:独占一行,段落间有间隙 2.排版标签 ①.换行标签 1.代码:<br> 英文全称:break line ​ 2.特点:强制换行,单标签 ②.水平分割线 1.代码:<hr> 2.特点:单标签 3.文本格式化标签 标签说明b或strong加粗u或ins下划线i或em倾斜s或del删除线 4.引用标签 短引用:<q> 不会换行 长引用:<blockquote> 会自动换行 子曰<q>学而时习之,不亦说乎</q> <blockquote> 这句话是我没有说过的! </blockquote> 二.媒体标签 1.图片标签 1.代码:<img src="" alt=""> 其中src叫属性名,""叫属性值,两者合称属性标签 2.是单标签 3.注意点: 标签上可以存在多个属性,属性之间以空格隔开;标签名与属性之间必须以空格隔开。 4.alt属性是替换文本的意思,当图片加载失败,就显示alt的文本,加载成功不会显示。 🔺5.title属性是提示文本的意思,也就是当鼠标悬停时,才显示的文本(title属性不仅仅可以用于图片标签,还可以用于其 他标签) 6.width和height属性 表示宽度和高度。 ①如果只设置width和height中的一个,另一个设置会自动等比例缩放(此时图片不会变形) ② 如果同时设置了两个,则会导致图片变形 补充:7.图片的格式: jpeg(jpg):支持的图片颜色比较丰富,不支持透明效果,不支持动图 gif:支持的颜色比较少,支持简单透明,支持动图

C语言输出3个整数最大值的案例教程

思路分析: 先比出2个整数的最大值,然后用最大值和第三个整数比较从而求出3个整数的最大值。 我们今天用几种办法输出3个整数最大值。 方法一:使用if-else语句以及输入输出语句来编写。 方法二:使用三元运算符以及输入输出语句来编写。 方法三:使用自定义指针函数以及三元运算符来编写。 方法四:使用冒泡排序法以及输入输出语句来编写。 方法五:使用求数组最大值的方法来编写。 方法一代码如下: 方法一代码运行结果如下: 方法二代码如下: 方法二代码运行结果如下: 方法三代码如下: #include <stdio.h> int ptr(int *x, int *y,int *z ){//这三个指针形参会接收主函数传来的三个数字的地址 int d,e; d=*x>*y?*x:*y;//三元运算符 e=d>*z?d:*z;//三元运算符 return e;//返回e的值,e的值就是三个整数最大的值 } void main(){ int a,b,c,m; scanf("%d%d%d",&a,&b,&c); m=ptr(&a,&b,&c);//调用子函数,实参的值为数字对应的地址 printf("三个整数的最大值为%d",m);//打印输出三个整数的最大值 } 方法三代码运行结果如下: 方法四代码如下: #include <stdio.h> #define N 3 void main(){ int arr[N];//定义一维数组 int i,d;//定义变量 printf("请输入三个整数:"); for(i=0;i<3;i++){ scanf("%d",&arr[i]); }//从键盘输入数值,给一维数组赋值 printf("数字从小到大排序为:"); printf("\n"); for(i=0;i<N;i++){ if(arr[i]>arr[i+1]){ d=arr[i]; arr[i]=arr[i+1]; arr[i+1]=d; } }//使用冒泡排序法,按从小到大排序 for(i=0;i<N;i++){ printf("%d\t",arr[i]); }//输出按从小到大排序完的数字 printf("\n"); printf("三个整数的最大值为%d",arr[N-1]); //一维数组的最后一个值就是三个整数的最大值,所以输出arr[N-1]; } 方法四代码运行结果如下:

【宜搭】低代码开发师高级认证实操题1难点指导

难度: 较难 知识点: 远程数据源 表单创建 表格组件使用 js增删改查功能代码编写 在本文中,我将根据题目的每一点要求,对于我在实操过程中遇到的难点进行比较详细的介绍,供大家参考,希望能够对大家有所帮助。 解题步骤: 创建页面 根据要求创建两个普通表单和一个自定义页面,分别为进行中待办、已完成待办和Todolist。具体相关组件的选用可以参考如下: 图1.1 Todolist页面 图1.2 进行中待办表单 注意: 其中进行中待办和已完成待办所构成的组件基本相同,操作列功能也基本相同,可直接复制粘贴。整个Todolist页面的页头部分可使用宜搭模板里的“待办项目”。 功能实现 1 数据展示 所涉及到的数据源 图2.1 获取进行中待办的数据源 注意: 参数formUuid的值为表单的Id,即APP_XXX 图2.2 获取已完成待办的数据源 注意: 同理于进行中待办,实际上接口可复用,只需在js面板调用接口,将对应的formUuid值赋值给参数即可,感兴趣可自行修改。 所涉及的全局变量 图2.3 进行中待办表格展示数据变量 图2.4 已完成待办表格展示数据变量 以下变量在编辑搜索功能时会有用 图2.5 进行中待办表格接口返回数据变量 图2.6 已完成待办表格接口返回数据变量 访问接口获取表单数据的代码 //获取进行中待办数据 export function getTodoListData(){ this.dataSourceMap.getTodoTasks.load().then(res =>{ //console.log(res) //以下根据返回内容重构数据对象,使数据格式符合宜搭组件格式要求 let toDoData = [] for(let i=0; i<res.data.length; i++){ let tmpData = res.data[i].formData //此处另外添加formInstId属性,用于之后的复选框功能 tmpData['formInstId'] = res.data[i].formInstId //将每一个重构的对象存入到全局变量ToDoData toDoData.push(tmpData) } //表格展示数据源。其中,currentPage和totalCount的取值会影响到表格分页器的展示 this.setState({ toDoListData: { data: toDoData, currentPage: res.

【JavaEE】定时器的简单实现

目录 定时器 实现定时器 描述任务 保存任务 扫描任务 执行任务 定时器 在实现定时器之前,先来简单的了解一下什么是定时器。 定时器是软件开发中一个重要的组件。比如到了什么时候,干一件什么样的事情;多少秒之后干什么。本篇文章介绍的多长时间后干什么事情。 Java标准库中的定时器,所提供的类——Timer 核心方法是schedule()。这里只演示多久之后执行任务这个方法。 import java.util.Timer; import java.util.TimerTask; public class ThreadDemo25 { public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("这是任务1, 1000ms后执行"); } }, 1000); timer.schedule(new TimerTask() { @Override public void run() { System.out.println("这是任务2, 2000ms后执行"); } }, 2000); TimerTask task = new TimerTask() { @Override public void run() { System.out.println("这是任务3,3000ms后执行"); } }; timer.

VS2022跨平台开发找不到linux下的头文件

VS2022跨平台开发找不到linux下的头文件 使用vs2022跨平台开发: #include <iostream> #include <netinet\in.h> using namespace std; int main() { cout << "hello world" << endl; } 在vs上,代码高亮没有问题,但是提示找不到netinet\in.h头文件。 解决方法:修改包含路径里的斜杠。左斜杠改成右斜杠。【Linux使用右斜杠分割路径】 #include <netinet/in.h> 关联的注意点: 1、vs的工具、选项、跨平台、连接管理器、远程表头IntelliSense 管理器:负责将远程服务器上的头文件复制到本地,从而提供给vs,用于vs本地的代码语法高亮。 更新:可以重新复制一遍头文件到本地缓存。 浏览:可以查看保存在本地的头文件缓存,我的缓存地址是 “C:\Users*****\AppData\Local\Microsoft\Linux\HeaderCache\1.0-1008359268\usr”,可以看到这个目录下有usr文件,其中包含了linux下的通用头文件。 我这的缓存,能够找到in.h文件,这就是为啥vs的语法高亮没有问题。 2、vs编译,是将本地源文件复制到远程linux环境上,查看gcc的默认include路径: #gcc gcc -print-prog-name=cc1plus -v #g++ g++ -print-prog-name=cc1plus -v 我这里的Linux环境默认包含了/user/include,里面也有in.h文件。

深度学习TensorFlow—GPU2.4.0版环境配置,一文简单易懂详细大全,CUDA11.0、cuDNN8.0

深度学习TensorFlow—GPU2.4.0版环境配置,一文简单易懂详细大全,CUDA11.0、cuDNN8.0 前提:电脑拥有英伟达独立显卡!!!,并且安装了anaconda!!! 前提:电脑拥有英伟达独立显卡!!!,并且安装了anaconda!!! 前提:电脑拥有英伟达独立显卡!!!,并且安装了anaconda!!! 本文简单易懂,现在的电脑,一般都是显卡驱动版本超过450的,在Anaconda Prompt中输入查看 nvidia-smi 比如我的查看显示驱动版本是496.76,CUDA支持版本最高到11.5,根据下面的GPU版本和CUDA、cuDNN对应版本,我选择了安装 tensorflow_gpu-2.4.0 版本。 一、TensorFlow各个GPU版本CUDA和cuDNN对应版本整理(部分): 二、安装流程: 1、首先安装上表所示的支持环境, Compiler (编译器)和 Build tools (构建工具): 需要官网下载MSVC2019,进行安装后,自带 Build tools 。 点击社区版下载,然后一直点击下一步。进行安装。 安装过程中出现如下需要选择工作负荷,可以先只勾选Python开发,然后点击安装,后续需要可再进行修改。 2、CUDA11.0以及cuDNN8.0下载安装本地文件安装: 选择11.00版本的CUDA,按照点击步骤进行下载到本地。 然后双击安装CUDA11.0: 可以现自定义一个临时空间,用于解压,用完便自动删除 选择自定义安装,取消勾选Visual studio intergration 和Display Driver 一直下一步,安装完成 下载cuDNN,cuDNN就相当于CUDA的补丁文件,下载时需要登陆账号,网络访问慢的,可以下载我的上传的百度网盘文件: 下载后解压,然后将文件夹复制到cuda安装文件夹里: 3、检查CUDA是否配置成功: 打开cmd,输入nvcc -V:,可以看到CUDA版本为V11.0: 进入此文件路径:(也就是安装的cuda文件夹的路径) C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\extras\demo_suite 进入cmd: 分别输入: .\bandwidthTest.exe .\deviceQuery.exe 最后执行结果为Pass,说明配置好了!!! 4、anaconda配置虚拟环境Tensorflow24: 打开Anaconda Prompt,创建一个虚拟环境,python版本为3.8: conda create -n Tensorflow24 python=3.8 进入环境,安装命令: conda activate Tensorflow24 ##进入环境 pip install tensorflow==2.4.0 -i https://pypi.mirrors.ustc.edu.cn/simple 安装成功后需要单独安装keras版本与tensorflow版本一致,

3.1 卷积神经网络的应用领域|卷积的作用|卷积特征值的计算方法|得到特征图表示|步长与卷积核大小对结果的影响|边缘填充方法

文章目录 卷积神经网络的应用领域卷积的作用卷积特征值的计算方法得到特征图表示步长与卷积核大小对结果的影响边缘填充方法 卷积神经网络的应用领域 检测任务分类与检索超分辨率重构医学任务无人驾驶NVIDIA Tegra X1(显卡 GPU) 卷积的作用 卷积神经网络(cnn)与传统神经网络(nn)的区别: 传统神经网络是将像素点输入,例如333就是将27个像素点输入进去,而对于卷积来说就是直接输入三维空间333进去类似右边的一个空间结构。 整体架构: 输入层(也就是一张照片)卷积层(提取特征)池化层(压缩特征)全连接层 卷积层通过先将32325分块,取其中的一块出来,再从中根据提取的像素点矩阵与w权重矩阵进行相乘得出相对应的特征值。 卷积特征值的计算方法 首先先理解一个概念:三颜色通道实际上就是将一张照片的图片实际上可以分成三张,比如RGB通道,实际上就是R通道的一张照片,G通道的一张照片,B通道的一张照片。 卷积内元素相乘,不同组相加,值得关注的是,仍需要加上b(偏置值)基本公式: 不同通道之间的数字直接进行相加。 得到特征图表示 卷积的结果是得到一张特征图: 即右边绿色的特征图,但是实际上我们传入的数据实际上是有多组数据的,也就是说我们最后得出的特征图也是有多份的,叠加在一起又是一个三位的矩阵。 具体的计算过程: 先进行分析:竖着的3个代表着三个颜色通道,然后右边: 这个代表着有两组特征图。具体的计算过程就是: -5 = (01+01+01+1-1+2*-1+20+1-1+11+20)+其他的两个通道的相对应的值(一个是0一个是-3)+偏置值b(1) 上述就是第一个特征图的一行二列的一个元素的计算过程。其他的也相同。 然后由于有两个特征图,所以相同位置可以计算出两个不同的值,也就是最后得出的也就有两张图表。 步长与卷积核大小对结果的影响 实际上我们的卷积过程并不是只有一步,实际上我们是先将有的图如下图所示的32323的图片做一次6特征图的卷积,得到28286的三维矩阵,拿这个三维矩阵再次去做10特征图的卷积,得到242410的三维矩阵······这也就是堆叠的卷积层。 卷积层涉及的参数: 滑动窗口步长(即取窗口时下一组距离本组的距离)卷积核尺寸(图为3*3的卷积核)边缘填充(详见下)卷积核个数(特征图个数) 边缘填充方法 可以看到+pad 1,实际上就是在外围的边界加上了一圈0,目的是为了缓解内部的贡献程度更大,外部的贡献程度更小的边界效应。

Oracle计算环比浅谈

转自:微点阅读 https://www.weidianyuedu.com 环比就是今年第n月与第n-1月或第n+1月比;同比就是今年第n月与去年第n月比。 建测试表,假设是个销售数量表: create table t (dt date,cnt number); 随便插入些测试数据,最后表的内容如下: DT CNT ---------- ---------- 2012-02-09 15 2012-02-21 2 2012-03-23 1 2012-03-23 5 2012-04-23 2 2012-05-12 20 2012-07-01 20 2012-07-21 20 显示环比,如果某个月没有销售,就有点儿麻烦。 先想个办法,显示本年度的1至12月,有个很有技巧的技术来实现: SQL> set pagesize 20 SQL> with m as (select "2012-"||lpad(rownum,2,"0") v from dual connect by level<=12) select * from m; V --------- 2012-01 2012-02 2012-03 2012-04 2012-05 2012-06 2012-07 2012-08 2012-09 2012-10 2012-11 2012-12 接下来就容易了,两个表外连,使用lag统计函数就可以了。 with m as (select "

最简单的python爬取网页小说

最简单的python爬取网页小说 坏境 爬取网址: https://www.biquzw.la/10_10218 使用到的python库requests、lxml 这些库都可以通过pip进行安装,如pip install requests 用到的浏览器插件:xpath helper 这个插件和lxml配合使用,可代替传统的re模块,也是就是正则表达式(这个很难记) 这里给大家介绍一个超快的pip下载方式 pip install lxml -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com 这个原理其实就是利用国内源进行下载 实现代码 import requests from lxml import etree url='https://www.biquzw.la/10_10218/5001501.html' #模拟浏览器 while True: headers={'User-Agent':'Mozilla/5.0 (Linux; Android 6.0.1; Moto G (4)) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Mobile Safari/537.36'} #请求网页 resp=requests.get(url,headers=headers) #编码响应得到的数据 resp.encoding='utf-8' #筛选所需要的内容 new_resp=etree.HTML(resp.text) info='\n'.join(new_resp.xpath("//div[@id='content']/text()")) title=new_resp.xpath("//div[@class='bookname']/h1/text()")[0] # print(info) # print(title) #找到下一章的url,利用递归进入循坏 url=new_resp.xpath("//div[@class='bottem']/a[4]/@href")[0] with open('斗罗大陆.txt','a',encoding='utf-8') as f: f.write(title + "\n\n" + info + "

Zookeeper的本地安装部署和分布式安装部署

文章目录 一. 本地模式安装部署1)安装前准备2)配置修改3)操作Zookeeper 1.2 配置参数解读 二. 分布式安装部署1)集群规划2)解压安装3)配置服务器编号4)配置zoo.cfg文件5)集群操作 客户端命令行操作1)启动客户端2)显示所有操作命令3)查看当前znode中所包含的内容4)查看当前节点详细数据 8)创建带序号的节点 一. 本地模式安装部署 1)安装前准备 (1)安装Jdk (2)拷贝Zookeeper安装包到Linux系统下 (3)解压到指定目录 [atbigdata@hadoop102 software]$ tar -zxvf zookeeper-3.5.7.tar.gz -C /opt/module/ 2)配置修改 (1)将/opt/module/zookeeper-3.5.7/conf这个路径下的zoo_sample.cfg修改为zoo.cfg; [atbigdata@hadoop102 conf]$ mv zoo_sample.cfg zoo.cfg (2)打开zoo.cfg文件,修改dataDir路径: [atbigdata@hadoop102 zookeeper-3.5.7]$ vim zoo.cfg 修改如下内容: dataDir=/opt/module/zookeeper-3.5.7/zkData (3)在/opt/module/zookeeper-3.5.7/这个目录上创建zkData文件夹 [atbigdata@hadoop102 zookeeper-3.5.7]$ mkdir zkData 3)操作Zookeeper (1)启动Zookeeper [atbigdata@hadoop102 zookeeper-3.5.7]$ bin/zkServer.sh start (2)查看进程是否启动 [atbigdata@hadoop102 zookeeper-3.5.7]$ jps 4020 Jps 4001 QuorumPeerMain (3)查看状态: [atbigdata@hadoop102 zookeeper-3.5.7]$ bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /opt/module/zookeeper-3.5.7/bin/…/conf/zoo.cfg Mode: standalone

指定不同版本的pcl

18.04里面安装了两个版本的pcl,一个是安装ros的时候安装的pcl1.8,另一个是安装的源码pcl1.12版本。一直相安无事,今天在我编译lego-loam的时候,突然就冲突了。卡了我两个小时,到处找原因,网上基本上没有相似的错误。最后在github的issue里面在到了一个类似的: Cmake not working · Issue #165 · RobustFieldAutonomyLab/LeGO-LOAM · GitHub 应该是共享库冲突,就是说ros原装的pcl1.8和我后来安装的源码版本的pcl1.12冲突了。 知道是什么错误就好处理了。 然后就指定了ros版本的pcl1.8,之后就成功catkin_make -j1了。 下面来记录一下怎么指定不同版本pcl,所有的操作只用在CMakeLists.txt中完成: 1.指定ros安装版本的pcl set(PCL_DIR "/usr/lib/x86_64-linux-gnu/cmake/pcl") find_package(PCL 1.8 REQUIRED QUIET) message("pcl_direction: " ${PCL_DIR} ) message("pcl_include_direction: " ${PCL_INCLUDE_DIRS} ) 在CMakeLists.txt中就这样修改就可以了,可以观察下message输出: 可以看到pcl_include_direction:中 /usr/include/pcl-1.8放到了第一个。 2.指定源码安装的pcl1.12版本 set(PCL_DIR "/usr/local/include/pcl-1.12") find_package(PCL 1.12 REQUIRED) message("pcl_direction: " ${PCL_DIR} ) message("pcl_include_direction: " ${PCL_INCLUDE_DIRS} ) message输出: /usr/local/include/pcl-1.12排到了首位。 比较容易,记录一下,免得以后碰到类似的问题,找记录就好。

【SFND_Lidar_Obstacle_Detection】代码笔记

源代码链接: https://github.com/williamhyin/SFND_Lidar_Obstacle_Detection 激光雷达数据: x,y,z,indensity(可用于评价物体的材料性质) 数据格式 PCD:点云数据(x, y, z, i),点云数据的坐标系与汽车的本地坐标系相同,在这个坐标系中, x 轴指向汽车的前部, y 轴指向汽车的左侧. 此外, z轴指向车的上方. PCL库 广泛应用于机器人技术领域, 用于处理点云数据, 网上有许多教程可供使用. PCL 中有许多内置的功能可以帮助检测障碍物. 本项目后面会使用 PCL内置的分割、提取和聚类函数. 你在这里可以找到PCL库的文档. Steps For Obstacle Detection Stream PCD 首先需要流式载入激光点云数据 (question1:如何在线使用?直接读取雷达数据,可以借鉴loam的写法?) template<typename PointT> std::vector<boost::filesystem::path> ProcessPointClouds<PointT>::streamPcd(std::string dataPath) { std::vector<boost::filesystem::path> paths(boost::filesystem::directory_iterator{dataPath},boost::filesystem::directory_iterator{}); // sort files in accending order so playback is chronological sort(paths.begin(), paths.end()); return paths; } // #################################################### ProcessPointClouds<pcl::PointXYZI>* pointProcessorI = new ProcessPointClouds<pcl::PointXYZI>(); std::vector<boost::filesystem::path> stream = pointProcessorI >streamPcd("../src/sensors/data/pcd/data_1"); auto streamIterator = stream.

使用Docker打包镜像并发布

1、docker介绍 Docker 是一个开源的应用容器引擎,以镜像的形式进行发布。docker的图标是一个大鲸鱼驮着许多集装箱在海上航行。大鲸鱼就是docker,集装箱就是一个个容器。容器是完全使用沙箱机制,相互之间不会有任何接口,每个容器都有自己独立的环境(环境设置、网络、文件系统等)就像一个个集装箱隔离开来,彼此没有任何联系。而每个箱子,又可以打包成一个新的镜像,放到其它服务器的docker环境中直接运行,不再需要重复安装程序运行环境。 1.1、docker镜像 docker镜像其实就类似于虚拟机镜像,操作系统镜像。是一个只读的模板,一个独立的文件系统,包括运行容器所需的数据,可以用来创建新的容器。我的理解镜像就相当于安装包安装文件这种,你docker pull下来的是一个安装包,然后docker会自动给你安装上去。 1.2、docker容器 docker容器,每一个单独的容器其实就相当于一台独立的服务器,docker通过容器技术把这个服务器划分为一个个单独的互不干扰的子服务器。好处在于每个容器都是独立的,有自己独立的环境设置如果不用容器的话,我一台服务器要装jdk,要装tomcat,要装mysql,要装rabbitMQ等等,每装一个软件/中间件,我都有可能要单独去配置环境变量这种。有可能装着装着不同的软件之间有版本冲突什么的,可能装了这个结果那个就装不上了什么的,还要做兼容性配置。当然出于成本的考虑,你不可能一个服务器就装一个软件吧。所以最好的方法就是通过虚拟化技术,把一个大的服务器拆分成一个个小的独立的服务器,每个小服务器分别装相应的软件/中间件(一个小服务器就只装单独一个软件)。当然也可以在服务器里面再搭虚拟机,不过这样很麻烦,不如用docker一步到位好。 1.3、docker仓库 docker仓库,我的理解其实就和maven仓库Git仓库的作用差不多吧。反正就是一个专门放置镜像的地方。可以先在docker里配置仓库的地址,要哪些镜像直接就从这个docker仓库里pull下来。比如docker镜像加速: 其实那些所谓的镜像,就是一个个docker仓库嘛。说到这个仓库,我突然联想到之前2021年的时候有个叫什么“懒人专用,全网VIP视频免费去广告、全网音乐.....”的一个基于浏览器的脚本。反正就是可以让你免费看各个网站会员的视频音乐这种。其实那个所谓的脚本我用了以后发现其实原理很简单:首先他那个脚本可以检测到你当前正在观看的视频音乐的名称,然后出现一个悬浮图标,你点了以后就会从他的资源仓库中找到相应的资源再播放给你看。反正不是真的破解网站会员。一开始还蛮好用的,不过后来开始收费了而且不开会员还给你限速,我就没再用了。我感觉国内的很多镜像地址也应该是类似的原理吧,因为我们国家互联网防火墙的存在,所以普通人无法或者速度很慢去访问下载一些外网的资源。所以嘛,镜像地址要么就是像那个什么“懒人的脚本”一样,建一个自己的资源库收纳各种资源,你要用直接从他的资源库里面拿。要么可能一些企业是被政府授权有专门的通道可以访问外网,你用他们的镜像地址相当于就是“借道”。 1.4、docker镜像和容器 关于docker镜像和容器之间的关系,我看网上有两种说法: docker镜像相当于类,而容器相当于类new出来的一个对象。docker镜像是一个程序,程序是静态的,只是一串代码,而容器是程序启动后的一个正在运行的进程。 我个人比较认同第二种说法。 2、在linux上配置docker环境 我使用的是linux是Ubuntu,装在VMWare虚拟机里面的,下载iso镜像可以去:清华大学开源软件镜像站 | Tsinghua Open Source Mirror 2.1、安装docker(适用于Ubuntu) sudo apt-get update sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg \ lsb-release --然后添加GPG秘钥 curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg --加入官方仓库 echo \ "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null --用apt安装 sudo apt-get update sudo apt-get install docker-ce docker-ce-cli containerd.

【pytorch学习03】预训练图像识别分类预测

下载安装mmcv-full(openmmlab里面最基础的算法库):对视频进行逐帧的分析,把每一帧画面的中间结果保存到目录里,最后把所有帧的中间结果串成一个视频文件 ImageNet1000类别信息,用于检测算法实现效果的数据集 我们今天用的是别人已经训练好的模型 # 创建目录 import os # 存放测试图片 os.mkdir('test_img') # 存放结果图片 os.mkdir('output') 把图片换成视频/实时摄像头画面 Import os # 导入操作系统库 Cv2 导入opencv import os # 操作系统库 import cv2 # 导入opencv import pandas as pd # 数据处理 import numpy as np import torch # pytorch import matplotlib.pyplot as plt # 数据可视化,画图 # 载入预训练图像分类模型 from torchvision import models model = models.resnet18(pretrained=True) # 表示有18层网络,层数越高,深度学习越深 model = model.eval() # 设为评估模式 model = model.to(device) # 将模型放到设备GPU/CPU里面

yolov5源码解析(10)--损失计算与anchor

本文章基于yolov5-6.2版本。主要讲解的是yolov5在训练过程中是怎么由推理结果和标签来进行损失计算的。损失函数往往可以作为调优的一个切入点,所以我们首先要了解它。 一。代码入口 损失函数的调用点如下,在train.py里 代码入口:utils/loss.py 1.先说一下两个入参: p: 推理结果列表,3个元素对应三个输出层,每层都是bs, na, ny, nx, no具体的输出可以参考上一篇博客 yolov5源码解析(9)--输出_扫地僧1234的博客-CSDN博客_yolov5三个输出 targets: 标签tensor,n行6列,每一行是image_index,class,x,y,w,h,image_index只是相对于当前的batch的index,比如batchsize选4,也就是4张图,那image_index就会有0,1,2,3 这里涉及到dataset和dataloader的相关代码,后面再补上具体的解析~~,不过先简单说两点 (1)dataset的代码在utils/dataloaders.py的LoadImagesAndLabels类里,主要是__getitem__函数,并且yolov5默认是会开启mosaic数据增强的,它会把当前的图和随机再选出的3张图合成一张图,那么对应的标签targets自然就是4张图的标签了,不过合成之后就是当成一张图来用,所以targets的image_index最终是同一个index。比如像下图。 (2)targets每行首位的image_index是在LoadImagesAndLabels.collate_fn4里面填上的,即是在dataloader层面完成的。 二。计算方法 先简单讲一下损失函数的计算逻辑 损失函数分三部分: (1)分类损失Lcls (2)置信度损失Lobj (3)边框损失Lloc 这三者的权重都是可以设置的,在data/hyps/hyp.scratch-low.yaml中,如下图 注:默认用的超参数的配置文件就是data/hyps/hyp.scratch-low.yaml,如果你想改成别的文件的话可以自己在训练命令行中指定--hyp参数 1.分类损失 采用nn.BCEWithLogitsLoss,即二分类损失,你没听错,就是用的二分类损失,比如现在有4个分类:猫、狗、猪、鸡,当前标签真值为猪,那么计算损失的时候,targets就是[0, 0, 1, 0],推理结果的分类部分(推理结果即输出的格式,具体可以上一篇博客 yolov5源码解析(9)--输出_扫地僧1234的博客-CSDN博客)也会有4个值,分别是4个分类的概率,就相当于计算4次二分类损失,取均值,从原理上来说自然也是可以的。并且还有如下原因: (1)还可以计算多标签分类损失 (2)后面讲到的置信度损失也是用的BCEWithLogitsLoss,这两者都用同一种损失更容易进行平衡 (3)用BCE就是得到了更好的效果,如果大家能证实CrossEntropy的效果更好,是可以去联系yolov5的作者的哦 以下贴出作者的答复 https://github.com/ultralytics/yolov5/issues/5401 这边要提到一个有意思的东西,就是yolov5里面的各种参数值,各种网络结构(比如C3),都不是作者凭空想象拍脑袋定的,都是基于经验、实验效果来定的,当然也不排除会有一些能改进的地方,比如Focus层就被改掉了~~ 还三点要补充: (1)按照640乘640分辨率,3个输出层来算的话,P3是80乘80个格子,P4是40乘40,P5是20乘20,一共有8400个格子,并不是每一个格子上的输出都要去做分类损失计算的,只有负责预测对应物体的格子才需要做分类损失计算(边框损失计算也是一样)。至于哪些格子才会负责去预测对应的物体,这个逻辑下面再说。 (2)分类的真值也不一定是0或1,还可以作label smoothing,感兴趣的话可以看一下相关代码和论文 这个label smoothing是在命令行参数里指定的,默认是0,就是没使用。 (3)分类损失的权重(超参数hyp['cls'])在train.py里会做相应的修正 首先box,cls,obj三个参数都会乘以一个3/nl,nl就是输出层数,默认是3层,3层的损失是相加的。所以如果改为5层,那损失自然要按比例修正一下。 然后cls还会乘以nc/80,nc就是分类数,80是coco数据集的80个分类,如果自己的数据集只有4个分类,那就会乘以4/80。为啥要这样呢?可能是为了平衡各个输出,BCEWithLogitsLoss默认用的计算策略是'mean',即求均值,也就是说80个分类,对应了80个通道的输出,计算损失时是求均值。而4个分类,计算损失也求均值。那这两个值其实会差不多。但是80个通道的值与4个通道的值在损失中应当占有的比例应该是不一样的,应该成正比(有可能这跟采用BCE损失相关)。所以如果变成4通道,那就应该减小它的权重。----只是个人猜测啊,暂时先不去求证了,留坑留坑~~ 2.置信度损失 上面已经说了,也是BCEWithLogitsLoss,不过置信度是每一个格子都要做损失计算的,因为最终在使用的时候我们首先就是由置信度阈值来判断对应格子的输出是不是可信的。置信度的真值并不是固定的,如果该格子负责预测对应的物体,那么置信度真值就是预测边框与标签边框的IOU。如果不负责预测任何物体,那真值就是0(不过看代码的话里面还有一个gr参数,然后作者说这个是GIOU的一个rate值,但我暂时并没有找到哪儿能改这个值,这个值初始值就是1,暂时先留个坑) 另外还要补充一下的是BCEWithLogitsLoss有一个pos_weight参数 默认都是1.0(好,相关超参数集齐了) 如果pos_weight就是1的话,那相关公式就是下面这样的(图取自pytorch官方文档) 而如果不是1呢,它是用来平衡正负样本损失的,如下,就是pc,这边的c指的是不同的分类,对于置信度来说就相当于1个分类了,从如下公式可以看出,如果标签为正样本,即ync=1,那这个pc才有效,否则是负样本,算的是后半部分值。 所以如果我们想提高recall召回率,即正样本如果推理成负样本,那损失要大一些,那么就可以提高pos_weight的值,但这样就会降低精度,因为模型更倾向于推理出更多的正样本(尽管可能会提升FP false positive的值)。所以如果相反,要提升精度,自然是降低pos_weight的值。 但是如果正负样本本身就不平衡,比如正样本100个,负样本300个,如果要平衡正负样本,那pos_weight就应该设置为3。 不过这边有一个问题了,之前说了三层一共会有8400个格子啊,而实际上负责预测对应的物体的格子只占一小部分,甚至一小小部分,正负样本不平衡啊,为啥这个pos_weight仍然是1呢? 这个问题需要从几方面入手: (1)首先作者做过实验,他发现与其提升pos_weight,不如直接提升置信度整体的权重效果更好,如果提升pos_weight,那可能会导致提升FP,出现更多的假正例。 可以看看这个问题(虽然它其实问的是另一个问题~~) Why Objectness Loss is Scaled with Image Size? · Issue #6192 · ultralytics/yolov5 · GitHub

单片机开发中常用到的C语言中关于数组和字符串的函数

常用到的关于操作空间(数组,堆空间)时的函数 > memset()函数 所在位置:string.h 函数声明: void *memset(void *str, int c, size_t n) str – 指向要填充的内存块。 c – 要填进去的值。(该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式) n – 要被设置为该值的字符数(要填入几个空间)。 作用: 对数组或堆空间初始化或者重初始化 eg: 在定义了一个数组或堆空间时,要使数组的每个空间或是堆的每个空间都变成你想要的值时 int arry[100]; memset(arry,1,100); 如此即可使数组100个空间的值都变成:1 当数组或堆在存放了一组数据时,想要把这个数组重新初始化时 int arry[10] = {1,2,3,4,5,6,7,8,9,0}; //数组现在存放的数据 memset(arry,0,10); 如此即可使得数组所有空间重新初始化 > memcpy()函数 所在位置:string.h 函数声明: void *memcpy(void *str1, const void *str2, size_t n) str1 – 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。 str2 – 指向要复制的数据源,类型强制转换为 void* 指针。 n – 要被复制的字节数。 作用: 将数据从一个空间拷贝到另一个空间 eg: 将数组arry从二之后的所有值复制到堆空间arry1第五个空间之后的地方 /* 将数组arry从二之后的所有值复制到堆空间arry1中*/ int arry[10] = {1,2,3,4,5,6,7,8,9,0}; //数组现在存放的数据 int *arry1 = (int *)malloc(13*sizeof(int));//创建个堆空间 memcpy(arry1[5], arry[2], 8); 如此即可使数组数组arry的值复制到arry1中

【JavaEE】阻塞队列 + 生产者消费者模型

目录 阻塞队列 阻塞队列的使用 生产者消费者模型 模型的两个好处 1. 降低耦合 2. 削峰填谷 简单实现阻塞队列 阻塞队列 阻塞队列是在一般的队列上升级而来的。 对于队列为空时,如果还想取队列中的元素,此时阻塞队列就会进行阻塞。 对于队列为满时,如果还想往队列中放元素,此时阻塞队列就会进行阻塞。 阻塞队列的使用 阻塞队列的具体使用由这个接口 BlockingQueue<>实现。 可以看到,该接口继承了队列,所以它有队列的所有方法。不过在使用阻塞队列时,我们一般只使用以下两种方法 方法说明void put(value)该方法是往队列里面添加元素,满了就阻塞Object take()该方法是取出队列的元素,空了就阻塞 其他的方法没有阻塞功能。 当我们实例化的时候可以看到,有以下三种实现方式。 简单使用一下阻塞队列。 import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class ThreadDemo21 { public static void main(String[] args) throws InterruptedException { // 这个队列的空间大小设置为 3 BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(3); blockingQueue.put(1); blockingQueue.put(2); blockingQueue.put(3); // 因为只有一个主线程 // 当往队列里添加第四个元素时, 这是队列就会进行阻塞 blockingQueue.put(4); // 以下代码执行不到了 int ret = blockingQueue.take(); System.out.println(ret); ret = blockingQueue.take(); System.out.println(ret); ret = blockingQueue.

[C/C++]对象指针

对象指针 1.对象指针变量 和基本类型变量一样,对象在初始化之后也会在内存中占有若干字节的内存空间。因此在程序中,我们可以通过对象名或对象的地址来访问该对象。对象指针变量就是一个用于保存对象在内存中存储空间首地址的指针变量,它与普通数据类型的指针变量有相同的性质。 声明对象指针变量的语法格式为: 类名 *对象指针名; 例如,声明exam类的对象指针obp; exam *obp; 对象指针声明后,需要先赋值(使它指向一个对象)后使用。取得一个对象在内存中首地址的方法与取得一个变量在内存中首地址的方法一样,都是通过取地址运算符"&";例如: exam ob; exam *obp; *obp = &ob; 最后的赋值表达式表示表达式&取对象ob在内存中的首地址并赋值给指针变量obp,指针变量obp指向ob在内存中的首地址。 对象指针变量赋值后,我们就可以通过该指针来访问它所指向的对象的成员。使用对象指针访问对象成员的语法形式为: 对象指针名->成员名; 对象数组的每个元素都是一个对象,都有地址,我们也可以使用对象指针指向对象数组的元素。使用方式和上面所述指向对象的指针变量类似。 case 1:用对象指针引用单个对象成员 #include <iostream> using namespace std; class A{ private: int x; public: void set_x(int a){ x = a; } void show_x(){ cout<<x<<endl; } }; int main(void) { A *ptr,ptr1; ptr1.set_x(2); ptr1.show_x(); ptr = &ptr1; ptr->show_x(); return 0; } 运行结果如下: case 2:用对象指针引用对象数组 #include <iostream> using namespace std; class A{ private: int x; public: void set_x(int a){ x = a; } void show_x(){ cout<<x<<endl; } }; int main(void) { A *ptr,ptr1[2]; ptr1[0].

将像素转换为 dp

问: 我为分辨率为 480x800 的 Pantech 设备创建了我的应用程序,其高度和宽度以像素为单位。 我需要为 G1 设备转换高度和宽度。我认为将其转换为 dp 将解决问题并为两种设备提供相同的解决方案。 有什么简单的方法可以将像素转换为 dp?有什么建议么? 答1: HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com Java代码: // Converts 14 dip into its equivalent px float dip = 14f; Resources r = getResources(); float px = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dip, r.getDisplayMetrics() ); 科特林代码: val dip = 14f val r: Resources = resources val px = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dip, r.displayMetrics ) Kotlin 扩展: val Number.toPx get() = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics) huntsbot.com全球7大洲远程工作机会,探索不一样的工作方式

Xcode 项目的 Git 忽略文件

问: 将 Git 与 Xcode 结合使用时,我应该在 .gitignore 中包含哪些文件? 答1: 一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会 我之前使用的是票数最高的答案,但它需要进行一些清理,所以这里对 Xcode 4 进行了重做,并进行了一些改进。 我已经研究了这个列表中的每个文件,但其中有几个在 Apple 的官方 Xcode 文档中不存在,所以我不得不进入 Apple 邮件列表。 Apple 继续添加未记录的文件,可能会破坏我们的实时项目。这个恕我直言是不可接受的,我现在已经开始在每次他们这样做时记录错误。我知道他们不在乎,但也许会让他们中的一个人更公平地对待开发人员感到羞耻。 如果您需要自定义,可以使用以下要点:https://gist.github.com/3786883 ######################### # .gitignore file for Xcode4 and Xcode5 Source projects # # Apple bugs, waiting for Apple to fix/respond: # # 15564624 - what does the xccheckout file in Xcode5 do? Where's the documentation? # # Version 2.6 # For latest version, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects # # 2015 updates: # - Fixed typo in "

探索 Docker 容器的文件系统

问: 我注意到 docker 我需要了解容器内发生了什么或其中存在哪些文件。一个例子是从 docker index 下载图像——你不知道图像包含什么,因此无法启动应用程序。 理想的情况是能够通过 ssh 进入它们或等效的。是否有工具可以做到这一点,或者我对 docker 的概念化认为我应该能够做到这一点是错误的。 答1: 一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会 这里有几种不同的方法… A)使用 docker exec(最简单) Docker 1.3 或更高版本支持与 nsenter 类似的命令 exec。此命令可以在已经运行的容器中运行新进程(容器必须已经运行 PID 1 进程)。您可以运行 /bin/bash 来探索容器状态: docker exec -t -i mycontainer /bin/bash 见Docker command line documentation B) 使用快照 您可以通过这种方式评估容器文件系统: # find ID of your running container: docker ps # create image (snapshot) from container filesystem docker commit 12345678904b5 mysnapshot # explore this filesystem using bash (for example) docker run -t -i mysnapshot /bin/bash 这样,您可以在精确的时刻评估正在运行的容器的文件系统。容器仍在运行,不包括未来的更改。

(已解决)jar!/BOOT-INF/classes!/application.yml (No such file or directory)

Spring Boot 今天在开发SpringBoot项目时,写了以下代码: String path = ClassUtils.getDefaultClassLoader() .getResource("") .getPath(); Reader reader = new FileReader( path + "/application.yml" ); 本意是通过获取classpath 类路径,然后读取application,yml中的内容。在本地的 IDEA 环境中测试时,程序正常,可以跑通。 但是一旦将程序打成jar包,便会报错: Caused by: java.io.FileNotFoundException: file:csdn-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/application.yml (No such file or directory) 可以看到文件路径出现了奇怪的感叹号!,这导致路径无法被正确匹配。 问题产生原因:当我们使用文件路径访问文件时,该路径下的文件必须是可访问的,而jar文件本质是上是一个压缩文件,需要解压才能访问,所以程序会直接报错。 解决办法:使用.getResourceAsStream(),不读文件路径,直接读取文件流。 InputStream input = ClassUtils .getDefaultClassLoader() .getResourceAsStream("application.yml"); Reader reader = new InputStreamReader(input, "UTF-8");

Android项目接入React Native方案

本篇文章主要介绍在现有的Android项目中接入React Native的接入过程,分析接入过程中的一些问题和解决方案,接入RN的平台为Android,开发环境为Mac,开发工具为Android Studio。 一、环境配置 1、Android配置 因为是现有的Android项目集成RN,所以关于Android方面的SDK,JDK,环境变量配置不做过多的介绍。需要注意的是环境变量的配置: 终端输入:$ open -e ~/.zshrc export ANDROID_HOME=/Users/username/Library/Android/sdk export PATH=$PATH:$ANDROID_HOME/tools export PATH=$PATH:$ANDROID_HOME/tools/bin export PATH=$PATH:$ANDROID_HOME/platform-tools export PATH=$PATH:$ANDROID_HOME/emulator export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_181.jdk/Contents/Home export PATH=$JAVA_HOME/bin:$PATH:. export CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:. 使环境变量生效:$ source ~/.zshrc 2、React Native配置 (1)安装 Node 和 Watchman 我们推荐使用Homebrew来安装 Node 和 Watchman。在命令行中执行下列命令安装(如安装较慢可以尝试阿里云的镜像源 https://developer.aliyun.com/mirror/homebrew): $ brew install node $ brew install watchman # 使用nrm工具切换淘宝源 $ npx nrm use taobao 如果之后需要切换回官方源可使用 $ npx nrm use npm (2)安装Yarn Yarn是 Facebook 提供的替代 npm 的工具,可以加速 node 模块的下载。

Taro升级3.5.10版本后出现swc相关编译报错【windows】

问题: Taro v3.5.10 Tips: 1. 预览模式生成的文件较大,设置 NODE_ENV 为 production 可以开启压缩。 Example: $ set NODE_ENV=production && taro build --type alipay --watch thread '<unnamed>' panicked at 'failed to register unwind information: "unsupported unwind information"', C:\Users\runneradmin\.cargo\registry\src\github.com-1ecc6299db9ec823\wasmer-engine-universal-2.3.0\src\code_memory.rs:199:18 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace failed to handle: failed to register unwind information: "unsupported unwind information" 解决方案: @swc/core 降版本到1.3.3

libmodbus的安装编译教程

1.下载libmodbus 方法一: sudo apt install libmodbus 方法二: https://github.com/stephane/libmodbus/ 方法1有可能无法获取到源,那么就用方法2从git拉取下来。如果git拉失败了,就需要去网上找源码下载了。(csdn不让我上传) 2.编译 后面教程是基于方法二,把modbus源码下载下来的教程。如果使用方法一则不需要纠结编译问题。 首先解压压缩包 tar -zxvf libmodbus-3.1.6.tar.gz 然后进去文件夹, 执行./configure,然后再执行make install就可以安装到本地了。 如果使用库的时候程序报找不到库,可以使用搜索去找libmodbus.so,或者在/usr/local/lib目录下查看。然后将库的路径加到环境(后面路径根据实际添加) export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib 编译过程中问题: ①以上是在虚拟机ubuntu上编译时正常的,但是在一切裁剪过的linux系统上编译会有其他问题,主要都是因为其他库缺少的原因。 如产生错误:WARNING: 'aclocal-1.14' is missing on your system 详情参考:解决Ubuntun 12.04编译Mesa10.3 WARNING: 'aclocal-1.14' is missing on your system_arackethis的博客-CSDN博客 其主要就是缺少其他库的原因,本人在树莓派上安装以下库后,直接make即可正常 如 sudo apt install automake ②如果想要将src文件都提取出来自行编译成库,不要使用g++进行编译,否则会报错。直接用gcc编译即可。 使用 使用很简单,引用头文件 #include "modbus.h" ,链接的时候加上-lmodbus即可 具体函数例程可以查看tests文件夹里面的例程。

url、域名、IP、爬虫

(图片来自b站up主——编程八点档) ':' : 分隔主机域名 '/' :分隔主机域名和路径 '?' : 分隔路径和查询参数 '=' : 设定参数的值 '&' : 分隔不同的查询参数对 我们用浏览器搜索的时候,用的是关键字(查询参数) 我们可以通过修改查询参数,实现在同一个IP域名下,快速爬取不同的元素 IP地址:192.168.1.xx 域名:www.baidu.com(用字符化的形式来对计算机网络中的主机进行网络标识) 域名是为了保证每个网站服务器的访问地址是独一无二的,它需要向统一管理域名的集构或组织注册或备档 所有主机设备上网都需要IP地址,但并不是所有主机设备都需要申请域名 我们来找一下百度的ip地址 在cmd中输入ping www.baidu.com , 就可以看到查询到这个域名的ip地址 我们试试用IP访问: url采用的是ASCII编码方式,不是Unicode,所以url网址中不能有非ASCII的字符 我们在浏览器中输入关键字是中文啊?——因为浏览器已经对url里的中文进行了编码 我将网址复制下来之后其实是这样的: https://www.baidu.com/s?ie=UTF-8&wd=%E6%88%91%E5%9C%A8%E5%8A%AA%E5%8A%9B%E5%AD%A6%E4%B9%A0 编码 quote() 解码 unquote() from urllib import parse key_word = '我在努力学习' key_word_ascii = parse.quote(key_word) print(key_word_ascii) 会打印出一串ASCII字符:%E6%88%91%E5%9C%A8%E5%8A%AA%E5%8A%9B%E5%AD%A6%E4%B9%A0 如果要爬虫的话 涉及的代码: from urllib import parse, response from urllib import request key_word = '我在努力学习' key_word_ascii = parse.quote(key_word) print(key_word_ascii) response = request.urlopen("http://www.baidu.com/s?ie=UTF-8&wd{0}".format(key_word_ascii)) result = response.

三子棋(N子棋)游戏的保姆级超详细教程(C语言)

⭐博客主页:️CS semi主页 ⭐欢迎关注:点赞收藏+留言 ⭐系列专栏:C语言初阶 ⭐代码仓库:C Advanced 家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们的支持是我创作最大的动力,欢迎友友们私信提问,家人们不要忘记点赞收藏+关注哦!!! 写在前面(前言) 1. 何为三子棋: 三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了,但是三子棋在很多时候会出现和棋的局面。 2. 为什么要和人工智障玩三子棋: 这个问题也困扰了我很久,如果我和朋友一起玩的话,肯定是和棋,但人工智障我有概率能赢呀,计算机的运行是由人预先编制的,很简单,因为我还没学到Alphago那种强人工智能,只能欺负欺负简单的人工智障了。(ps.关于计算机的运行为什么是人预先编制的后期我会出一篇博客,关注我,不迷路~~) ~~~~~~~~~~~~~~~~~~~~~~~~~~正文开始~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 一、制作三子棋游戏的思路 制作游戏单(menu),让玩家选择玩游戏或者退出游戏。进入游戏后初始化棋盘并进行打印。三子棋函数的创立玩家先落子。计算机随机落子。判断哪一方胜利。玩家选择是否还玩游戏。(自动就会跳出来了) 二、详细步骤(附每一步代码) 要实现此游戏,需要创建几个模块,当然是为了方便啦,一个头文件和两个源文件。 test.c(测试逻辑)game.h.c(函数头文件)game.c(函数内容) (ps.括号里的命名比较具象,为了让读者能够更好理解该模块表达的意思) (一)游戏单的创建 void menu() { printf("\n"); printf("这是个三子棋的游戏,冒险者你准备好了吗?\n"); printf("如果你准备好了请扣个1,没准备好请扣个0\n"); printf("1.直接进入\n"); printf("0.那退出吧\n"); } void test() { int input = 0; do //这里是为了实现游戏的重复进行 { int input = 0; menu(); printf("请选择:>"); scanf("%d", &input); //玩家输入1或者0显示玩不玩游戏 switch (input) { //switch是分支选择是否开始玩游戏 case 1: printf("开始游戏\n"); game(); //game()是这个游戏的程序开始玩的函数 break; case 0: printf("退出游戏\n"); break; default: printf("输入错误\n"); break; } } while (input); //i是输入的是1或者0,此时,非0的意思是继续游戏,0是退出游戏 } int main() { menu(); test(); return 0; } 大家到这里就有疑惑了,那个game();是个什么东东,这找了半天也没发现这个game();的表达式呀!客官且听我分析,在该文件中还有一个未定义的game();在抬头,后面会有模块写出game()函数的。

CSS中设置了宽度,但是其中的内容溢出而不换行

CSS中设置了宽度,但是其中的内容溢出而不换行 当我们为div标签或者p标签等设置了宽度,会出现文本溢出并且不会换行的情况,一般这种情况都是只有文本内容为单词或者纯数字的时候出现的。 原因是由于:浏览器在解析我们页面的时候,给这一串数字当成一个词了,这样就不会自动切断字符串而进行换行。 解决方法: 方法一: word-break: break-all; 方法二: word-break: break-word; 两种方法的区别在于: 方法一:内容到达指定宽度强行断句换行,一个单词显示不开将会截断换行继续展示; 方法二:当前单词在宽度内无法展示,整个单词换行展示; 举个例子: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> <title></title> <style type="text/css"> .div1{ width: 400px; word-break: break-all; } .div2{ width: 400px; word-break: break-word; } </style> </head> <body> <div class="div1">"Time," says the proverb, "is money". This means that every moment well-spent may put some money into our pockets.</div> <br/> <div class="div2">"Time," says the proverb, "

Chrome浏览器离线安装包下载方法

Chrome浏览器离线安装包下载 1、打开 Chrome 浏览器主页:http://www.google.cn/chrome 2、地址栏最后的网址是这样的:http://www.google.cn/chrome/browser/desktop/index.html 3、在网址最后加上:?standalone=1&platform=win64,回车键后打开的是 64位下载页面,点击“下载Chrome”按钮,得到的就是 Google Chrome 64位离线安装包 其中 ?standalone=1 指离线安装包,platform=win64 指64位Windows 版本。 如果加上的只是“?standalone=1”可以用来下载32位的Chrome离线包。用“mac”替换“win”,就可以下载 Mac 版本的了。

k8s之挂载本地磁盘到POD中

写在前面 本文一起看下如何挂载本地的磁盘到POD中。 1:都需要哪些API对象 现实世界中的存储设备有非常非常多的种类,如本文要分析的计算机磁盘,还包括NFS(一种网络磁盘存储协议),Ceph(一种分布式的文件存储系统),不管是哪种方式,最终都是通过将数据存储到硬盘来实现持久化,但是不同种类写入数据的方式是不相同的,k8s针对这些不同的存储目标进行抽象定义了PersistentValume API对象,如下: dongyunqi@mongodaddy:~/k8s$ kubectl api-resources|egrep -w 'PersistentVolume|KIND' NAME SHORTNAMES APIVERSION NAMESPACED KIND persistentvolumes pv v1 false PersistentVolume 现在不同存储系统的抽象已经有了,那么具体该怎么使用办呢?能不能让pv拥有这种能力呢?自然是可以的,但是这又不符合单一职责的原则了,所以对于这些存储系统的具体使用k8s又定义了一个新的API对象,Persistent Volume Claim,如下: dongyunqi@mongodaddy:~/k8s$ kubectl api-resources|egrep -w 'PersistentVolumeClaim|KIND' NAME SHORTNAMES APIVERSION NAMESPACED KIND persistentvolumeclaims pvc v1 true PersistentVolumeClaim 最后,这么多的存储系统,当多了之后,混杂在一起,势必造成混乱,为此k8s又定义了StorageClass来进行分类维护,如下: dongyunqi@mongodaddy:~/k8s$ kubectl api-resources|egrep -w 'StorageClass|KIND' NAME SHORTNAMES APIVERSION NAMESPACED KIND storageclasses sc storage.k8s.io/v1 false StorageClass 这样,需要用到的3个API对象我们就介绍完毕了,三者的关系我们可以参考下图: 下面我们看一个实际的例子。 2:挂载磁盘到POD中 毫无疑问,我们需要先定义磁盘的抽象PV,yaml如下: apiVersion: v1 kind: PersistentVolume metadata: name: host-10m-pv spec: storageClassName: host-test accessModes: - ReadWriteOnce capacity: storage: 10Mi hostPath: path: /tmp/host-10m-pv/ 主要属性介绍如下:

在maya中如何修正相机的枢轴点的变化导致相机动画导入引擎后不正确的问题

前言 最近工作中经常遇到外包回来的相机的枢轴点变化,甚至所有值归零后枢轴点也不在世界中心的情况,这种相机动画导入引擎就会出现和maya中相机对不上的情况,这里记录一下解决方法. 过程 基本思路就是计算出原有相机中心点的世界坐标位置,然后用一个新相机继承原有相机的动画,最后烘焙关键帧即可. 打开maya的节点编辑器,将原相机和新相机显示在图表上 首先我们忽略相机的旋转,我这里用一个球体代替,在节点编辑器中Transform节点给我们提供了Rotate Pivot但是,这个枢轴点是局部空间的(即:相机中心到枢轴点的向量),好在Transform节点也为我们提供了用于将局部空间变换为世界空间的矩阵,这里我们用节点PointMatrixMult(这个节点可能需要开启插件matrixNodes.mll才能找到),把这个局部坐标和世界变换矩阵相乘,即可得到枢轴点的世界空间坐标. 这样我们就找到了相机枢轴点的世界空间坐标,.因为我们之前说过相机的局部空间坐标是相机中心位置到相机枢轴点之间的向量,此时用相机枢轴点的坐标减去这个向量就可以得到,这里我们使用节点PlusMinusAverage并将Operation调整为Subtract来计算点和向量之间的减法. 可以看到此时小球已经和相机的中心点重合了,但需要注意此时我们的相机是不带旋转值的,如果我们此时对相机进行旋转,可以看到,相机的中心点在旋转后产生了位移. 这时,我们可以利用一个向量来帮助我们计算相机旋转后的中心点的位置,即相机在不旋转时,枢轴点指向相机中心点的向量,然后我们旋转这个向量,再使用相机枢轴点的坐标加上旋转后的向量即可得到相机旋转后中心点的位置.继续使用PlusMinusAverage来计算枢轴点指向相机中心点的向量,使用ComposeMatrix节点创建旋转矩阵,再次使用PointMatrixMult来计算旋转后的向量 需要注意的这次的PointMatrixMult需要勾选Vector Muitiply(不过目前的情况不勾选也没影响),这样我们就得到了旋转后枢轴点指向相机中心点的向量,最后用枢轴点的坐标加上这个向量即可同时还需要将老相机的旋转值传递给新相机.

Centernet算法

相比yolo,ssd,faster_rcnn等依靠大量anchor的检测网络,CenterNet是一种anchor-free的目标检测网络。Centernet将目标看作一个点,一个目标由一个特征点确定。centernet将输入的图片划分成若干个区域,每个区域存在一个特征点。centernet网络的预测结果会判断这个特征是否由对应的物体,以及物体的种类和置信度;同时还会对特征点进行调整获得物体的中心坐标;并且回归出物体的宽高。 一、网络结构 Centernet网络结构主要分成下面3个部分: 1、主干特征提取网络 Centernet用到的主干特征网络有多种,如一般是以Hourglass Network(主要用于人体姿态估计)、DLANet(Deep Layer Aggregation)或者Resnet等。原始的centernet输入输入网络图片的尺寸为3x512x512的时候,最后一个特征图的shape为(2048,16,16)。 2、上采样,获得高分辨率特征图 对于该部分,centernet利用三次反卷积进行上采样,这3个反卷积的输出通道数分别为256,128,64。每一次反卷积,特征图的高和宽会变为原来的两倍,因此,在进行三次反卷积上采样后,我们获得的特征图的高和宽变为原来的8倍,此时特征图的高和宽为128x128,通道数为64。此时我们获得了一个64x128x128的有效特征图(高分辨率特征图)。 3、Center head 通过上一步我们可以获得一个64x128x128的高分辨率特征图。这个特征图相当于将整个图片划分成128x128个区域,每个区域存在一个特征点,如果某个物体的中心落在这个区域,那么就由这个特征点来确定。 我们可以利用这个特征图进行三个卷积,分别是: 1)热力图预测,此时卷积的通道数为num_classes,最终结果为(num_classes ,128,128),代表每一个热力点是否有物体存在,以及物体的种类; 2)偏移预测,此时卷积的通道数为2,最终结果为(2,128,128),代表每一个物体中心距离热力点偏移的情况; 3)宽高预测,此时卷积的通道数为2,最终结果为(2,128,128),代表每一个物体宽高的预测情况; 二、heatmap(热力图)的理解和生成 1、heatmap的理解 CenterNet将目标当成一个点来检测,即用目标box的中心点来表示这个目标,预测目标的中心点偏移量(offset),宽高(size)来得到物体实际box,而heatmap则是表示分类信息。每一个类别都有一张heatmap,每一张heatmap上,若某个坐标处有物体目标的中心点,即在该坐标处产生一个keypoint(用高斯圆表示),如下图所示: 2、产生heatmap的步骤如下: 如下图左边是缩放后送入网络的图片,尺寸为512x512,右边是生成的heatmap图,尺寸为128x128(网络最后预测的heatmap尺度为128x128。其步骤如下: 1)将目标的box缩放到128x128的尺度上,然后求box的中心点坐标并取整,设为point 2)根据目标box大小计算高斯圆的半径,设为R 3)在heatmap图上,以point为圆心,半径为R填充高斯函数计算值。(point点处为最大值,沿着半径向外按高斯函数递减) (注意:由于两个目标都是猫,属于同一类别,所以在同一张heatmap上。若还有一只狗,则狗的keypoint在另外一张heatmap上) 3、heatmap高斯函数半径的确定 heatmap上的关键点之所以采用二维高斯核来表示,是由于对于在目标中心点附近的一些点,期预测出来的box和gt_box的IOU可能会大于0.7,不能直接对这些预测值进行惩罚,需要温和一点,所以采用高斯核。借用下大佬们的解释,如下图所示: 关于高斯圆的半径确定,主要还是依赖于目标box的宽高,其计算方法为下图所示。 实际情况中会取IOU=0.7,即下图中的overlap=0.7作为临界值,然后分别计算出三种情况的半径,取最小值作为高斯核的半径r 这部分代码如下: def gaussian_radius(det_size, min_overlap=0.7): height, width = det_size a1 = 1 b1 = (height + width) c1 = width * height * (1 - min_overlap) / (1 + min_overlap) sq1 = np.sqrt(b1 ** 2 - 4 * a1 * c1)

VMware Workstation Pro 16安装Windows 11

1:首先在机器中安装VMware Workstation Pro。 2:准备Windows 11的安装镜像。 3:安装Windows 11的系统要求,这个很关键不满足条件无法安装,其中我们只需要注意系统固件和TPM这两项就行。(最重要步骤的14-19步) 4:运行VMware Workstation创建新的虚拟机。 5:选择典型,下一步。 6:选择稍后安装操作系统,下一步。 7: 客户机操作系统选择Microsoft Windows,版本选择Windows 10 x64,下一步。 8:给虚拟机起个名字,根据实际情况选择存放的位置。 9:选择将虚拟机磁盘存储为单个文件,下一步。 10:点击自定义硬件。 11:根据实际情况和要求选择CPU和内存,可以去掉不需要的硬件比如打印机,点击关闭。 12:在点击完成。 13:点击编辑虚拟机设置。 14:这次我们主要是设置UEFI安装和TPM。其实上面的步骤和我们安装WIN7或者WIN10没有区别。点击选项。 15:点击选项中的高级 ,勾选安全引导。 16:在选项中点击访问控制,设置密码为添加TPM做准备。 17:点击加密,设置密码。记住密码,安装成功后启动虚拟机需要密码因为有TPM的存在。 18:回到硬件中点击,添加。 19:选择可信平台模块,点击完成。 20:在硬件中选择CD/DVD(SATA),在使用ISO映像文件,选择之前准备好的Windows 11镜像,点击确定。 21:点击开启虚拟机进行安装。 22:出现下面的界面不要急,等一会就好了。 23:等一会后出现下面的界面。我们选择EFI VMware Virtual SATA CDROM Drive(1.0)回车。 24:出现下面的界面按任意键。 25:出现了Windows 11的安装界面。 26:之后的过程有跳步,因为和安装其他系统没有什么区别。这里我们选择我没有产品密钥。 27:根据情况选择版本。 28:之后接受协议,自定义安装。选择新建分区。 29:应用。 30:确定。 31:下一步。 32:开始安装。 33:地区选择中国。 34:之后的设置根据情况选择。如果有微软账号可以用账号登录,如果没有随便输入一个也可以,他提示你错误,按照提示一步步选择就可以了,也可以点击登录选项,改为加入域本地登录。方法步骤太多了不截屏了。 35:安装完成。

【antd组件之ProTable,EditableProTable】

1. 每一列数据 // 每一列数据 // type是定义了一个新类型,每一个就是定义columns的dataIndex type GithubIssueItem = { url: string; id: number; number: number; title: string; labels: { name: string; color: string; }[]; state: string; comments: number; created_at: string; updated_at: string; closed_at?: string; }; 2. ProColumns配置项 // 所有table需要配置的属性,都可以在最前面定义,下面直接用 columns={columns}使用 // 定义了几列,每一列的配置 // 类型是ProColumns,相当于ProTable里面的columns列 // 列定义 /** * { title//列头显示文字 align//设置列里面文字的对齐方式 left,rignt,center className//列样式类名 colSpan//表头列合并 dataIndex//列数据在数据项中对应的路径,支持通过数组查询嵌套路径 key//React 需要的 key,如果已经设置了唯一的 dataIndex,可以忽略这个属性 render//生成复杂数据的渲染函数,参数分别为当前行的值,当前行数据,行索引 function(text, record, index) {} ellipsis//是否自动缩略 copyable//是否支持复制,会出现复制的小图标 valueEnum//值的枚举,会自动转化把值当成 key 来取出要显示的内容 valueType filedProps // valueType和fieldProps会把上面那个form查询表单渲染为select类型的下拉框 // 里面的值就是fieldProps里的options valueType: 'select', fieldProps:{ options: statusList }, render: (_: any, record: any) => { console.

锂离子电池热失控预警资料整理(三)

此前 个人搜集了一些锂电池热失控预警相关期刊、文献,并整理了一些个人认为重要的逻辑、知识点,希望通过此分享让有需要的人了解一些内容,如有问题欢迎同我探讨~ 锂离子电池热失控预警资料整理(三) 九、基于数据分析的锂离子动力电池热失控故障诊断研究_陈佳纯十、电动汽车用锂离子电池典型安全问题研究_梁栋滨【主】十一、车用锂离子动力电池热失控诱发与扩展机理、建模与防控_冯旭宁11.1 热失控机理11.2 热失控诱因11.3 绝热热失控安全等级划分 十二、大容量磷酸铁锂动力电池热失控预警策略研究十三、动力电池热失控报警信号策略研究(实车数据)十四、基于大数据驱动的集成模型车辆热失控预测14.1 基于概率密度的电压模型,基于概率密度的温度模型14.2 基于分布的异常电流识别模型14.3 基于信息熵 的单体一致性确定模型14.4 基于 SOC 过度充电和恒定因素 的风险评估模型 十五、车用锂离子电池热失控研究综述十六、电动汽车电池安全监控及预警策略研究16.1 动力电池监控预警方案设计16.2 报警策略及响应方案 十七、电动汽车热失控预警网关设计与实现 九、基于数据分析的锂离子动力电池热失控故障诊断研究_陈佳纯 内短路是电池热失控过程的共性环节。机械撞击,高温等外部作用导致的电池内短路从而造成热失控的过程持续时间很短,常常可以预知,而由于过度充放电等因素造成电池内枝晶生长,混入金属杂质等情况往往会导致电池自发内短路,这种自发内短路有很高的隐蔽性,初期阶段不明显,但是在末期时会在短时间内引发热失控。 图 是电池内短路发展演化过程,内短路初期电压下降和温度上升的速率都比较缓慢,之后电池内阻逐渐降低,导致放电电流增大,电压下降,同时产热速率大于散热速率,使电池内温度温度明显升高,最后使电池隔膜受热崩溃,使电池的正负极之间发生大面积短路,电池的端电压突降为 0。同时高温会触发热失控连锁反应,在短时间内释放出大量的热,使电池发生热失控。 十、电动汽车用锂离子电池典型安全问题研究_梁栋滨 电池滥用的概念: 电池滥用:由于电池管理系统中电池保护电路故障、使用环境的温度突变或者由于外界突发事件对电池造成机械损坏等,超出电池设计使用极限,从而造成电池的滥用。锂离子电池具有高能量密度、高功率密度及其采用了有机可燃性电解质溶液,当发生滥用时,在一定复杂条件下可能会引发电池的热失控,从而会引起突发的安全事故。特别是在电池组中,假如各单体电池处于不均衡状态,对电池组中的一个特定的单体电池,无异于处于滥用状态,该单体电池的不安全因素可能会引起整个电池组安全事故的发生。所以对电池滥用现象的研究越来越受 到重视。 【主】十一、车用锂离子动力电池热失控诱发与扩展机理、建模与防控_冯旭宁 在以内短路为代表的热失控诱因及其早期检测,热失控发生机理及其预警,热失控扩展机理及其抑制三个方面,实现了动力电池系统热失控的逐级防控。 11.1 热失控机理 在发生热失控的过程中,从低温到高温排序,锂离子动力电池将依次经历:高温容量衰减;SEI 膜分解;负极-电解液反应;隔膜熔化过程;正极分解反应;电解质溶液分解反应;负极与粘接剂反应;电解液燃烧等过程。 SEI 膜分解:起始温度大约为 80℃。负极-电解液反应:120℃。隔膜融化:PE隔膜融化,130℃;PP隔膜融化,170℃。正极分解反应:安全性,钴酸锂>三元(NCA>NCM)>锰酸锂>磷酸铁锂 LCO 钴酸锂:起始温度200℃。LMO 锰酸锂:起始温度152℃。LFP 磷酸铁锂:反应温度190-285℃。NCM 三元正极:起始温度211℃。 电解质溶液分解反应:200℃稍高一点开始。负极与粘结剂反应:起始温度240℃。 11.2 热失控诱因 三种滥用诱发方式之间,存在一定的内在联系。 机械滥用导致电池的变形,而电池的变形导致内短路的发生,即导致了电滥用的发生。电滥用伴随焦耳热以及化学反应热的产生,造成电池的热滥用。热滥用造成温度的升高,引发锂离子电池热失控链式反应,最终导致热失控发生。 11.3 绝热热失控安全等级划分 十二、大容量磷酸铁锂动力电池热失控预警策略研究 在预警模块的基础上,综合分析失控试验中各项特征参数的变化,为预警阈值范围的设定提供支撑。各试验中,目标电池安全阀打开时正极临界温度及临界温升速率,见表 2。因电池安全阀打开时,喷射气流存在较强的对流降温效果,导致电池正极温度出现先轻微下降再回升的现象,因此,临界温升速率取绝对值比较。对比过充失控试验与加热失控试验的临界温度参数发现,电池过充电引发的热失控进程较为缓慢,热失控临界温度值及临界温升速率值均明显小于加热失控。从热失控早期预警角度出发,取制造商规定的电池最高工作温度为温度预警下限,取过充试验临界温度参数为温度预警上限,即电池表面温度绝对值报警阈值范围为 60~75 ℃,电池表面温度温升速率报警阈值范围为 0. 5~1. 7 ℃ /s。 十三、动力电池热失控报警信号策略研究 文章提出一种电动汽车用动力电池热失控 报警信号策略。 热失控报警信号函数 y= f(a,b,c, d,T)。 a:单体最低电压低于设定值w则a=1,其余情况a=0;b:单体电压下降速率高于设定值x则b=1,其余情况b=0;c:单体最高温度高于设定值y则c=1,其余情况c=0;d:单体温度上升速率高于设定值z则d=1,其余情况d=0。T:T=nt,t为采样时间间隔。对上述4个任意参数,当变化达到T的持续时间才认为这一参数的条件判断成立。 (实车数据)十四、基于大数据驱动的集成模型车辆热失控预测 构建了一种集成的机器学习算法,通过分别考虑电压和温度、异常电流、单电池一致性和过充电风险因素,构建集成模型。

Android 屏幕适配

基本概念 相关术语 px:像素;dpi:即densityDpi,每英寸中的像素数;density:屏幕密度,density = dpi / 160;scaledDensity:字体的缩放因子,正常情况下和density相等,可以通过调节系统字体大小改变该值。 android中的dp在渲染前会将dp转为px,公式如下: p x = d e n s i t y ∗ d p px = density * dp px=density∗dp 限定符匹配 匹配规则:当前dpi > 更高的dpi > 更低的dpi 以图片为例,图片资源的文件夹分为mdpi、hdpi、xhdpi xxhdpi xxxhdpi等。 假设当前设备密度为xhdpi,文件夹为上述5种,则查找顺序为:xhdpi > xxhdpi > xxxhdpi > hdpi > mdpi 。 XML布局适配 动态加载布局 给res目录中的子目录加上“-限定符”,可以给不同设备提供不同的资源以及布局。 指定屏幕大小:-sw+指定大小 例如限定480到1080屏幕,1080以上屏幕:layout-sw480dp,layout-sw1080dp sw,Smallest-width,最小宽度限定符。 指定屏幕方向:-land、-port 创建自适应布局 思路:尽量不要把view宽高边距等写死,而是设置权重或百分比让其自适应。 缺点:绘图时为实现自适应需要反复测量计算布局的属性,增加开销。 方法: 使用LinearLayout时,通过设置layout_weight让各个视图自适应大小。 推荐使用 ConstraintLayout 构建自适应界面。 ConstraintLayout 百分比布局 设置水平和竖直方向百分比偏移,左上角为(0,0),右下角为(1,1)。 <TextView ... app:layout_constraintHorizontal_bias="0.2" app:layout_constraintVertical_bias="0.3" /> 设置宽高比 高固定,将宽设为高的两倍:将layout_width设为0,设置layout_constraintDimensionRatiov属性。

输出mysql数据库中文数据出现乱码解决方法

我们安装了mysql数据库之后,当我们去查询数据库的时候,会出现原本应该是中文的却出现乱码,所以这一期来讲讲怎么去解决这些烦人的乱码问题。 解决方法 查看数据库的编码格式: 打开cmd指令,登陆mysql,输入以下指令 show variables like 'char%'; 如果出现这种情况就要去修改编码格式了。 说明: character_set_client:客户端请求数据的字符集 character_set_connection:客户机与服务器连接的字符集 character_set_database:默认数据库的字符集;如果没有默认数据库,就会使用 character_set_server指定的字符集(建议不要随意更改) character_set_filesystem:把 character_set_client转换character_set_filesystem (默认为binary, 不做任何转换) character_set_results:返回给客户端的字符集 character_set_server:数据库服务器的默认字符集 character_set_system:系统字符集,默认utf8。(用于数据库的表、列和存储在目录表中函数的名字) 此时打开数据库目录,看到ini文件,然后进行配置文件的修改就行了 方法: 在mysql的my.cnf的配置文件中修改或添加下列: [client] default-character-set = utf8 [mysqld] character-set_server = utf8 这样就基本解决了。然后退出服务器,出现开启服务器,再次登陆,show variables like 'char%';查看编码格式 这时候就已经修改成功了,可以正常输出中文了 OK就到这里,thanks!

【UE】pak的mount(带源码解析)

本文使用的引擎版本为UE4.27 为了方便理解,文中选取的代码均为部分截取,只截取与小节相关的部分 文章目录 概述几个涉及到的结构Mount时机pak读取优先级目录优先级根据文件名定优先级综上所述 概述 正常的散文件加载是使用FFileHelper::LoadFileToArray等接口来读取文件内容。但pak作为一个类似于压缩包的格式,其中的文件无法直接使用这种方式读取。故需要使用mount来挂载。 mount操作告诉系统有哪些文件可以从pak中读到,并提供虚拟路径使系统可以通过FPakPlatformFile::CopyFile、FFileHelper::LoadFileToString等操作普通文件的方法操作pak中的文件 几个涉及到的结构 IPlatformFile:文件IO的接口,是整个文件系统的基类。该类及其子类以链式组织,每个实例存有其下层的引用,每层访问的时候都先查找自身,找不到才向下层查找。 FPakPlatformFile:继承于IPlatformFile,负责pak的mount。它的私有成员ExcludedNonPakExtensions记录了几个只应存在pak里的文件拓展:uasset、umap、ubulk、uexp、uptnl和ushaderbytecode。这些文件如果在pak里没有找到,就不再查找它的下层了。 FPakListEntry:定义在FPakPlatformFile内的结构体,有ReadOrder和PakFile两个属性。FPakPlatformFile中用几个TArray来记录mount到的pak FPakFile:Pak在C++中存储的形式。有PakFilename、LastUseTime、Info等成员 FPakInfo:Pak的提纲信息,存有版本号、哈希值、魔数、是否加密等 FPakEntry:Pak中单个文件的信息,存储文件大小、在pak中的偏移量、是否加密等 Mount时机 很多地方都会调到FPakPlatformFile::Mount进行pak的Mount,这里只分析引擎启动时进行的mount 引擎启动时进行的初始化mount位于 FPakPlatformFile::Initialize。如果使用命令行指定了PakFile单例,会在引擎PreInit的阶段通过ConditionallyCreateFileWrapper函数创建单例并调用 FPakPlatformFile::Initialize。如果没有在命令行中指定,则该初始化函数在EditorInit阶段才进行。后者的调用堆栈如下: pak读取优先级 概述中提到,mount的作用是为了提供一种读取pak文件的方法,使pak中的文件也能使用操作散文件的操作方法。即:mount并不是读取pak中的文件。故mount顺序其实对pak的读取优先级没有影响 那么pak读取的优先级到底取决于什么呢? 做热更需求的时候如何保证自己新添加的pak可以覆盖掉原来pak中的资源?答案是取决于FPakListEntry的ReadOrder:ReadOrder大的pak会覆盖小的pak的资源内容 // IPlatformFilePak.h struct FPakListEntry { FPakListEntry(): ReadOrder(0), PakFile(nullptr){} uint32 ReadOrder; TRefCountPtr<FPakFile> PakFile; // ReadOrder越大,优先级越高。故热更的时候只需要保证新pak的ReadOrder大于原来的pak即可 FORCEINLINE bool operator < (const FPakListEntry& RHS) const { return ReadOrder > RHS.ReadOrder; } }; 这个ReadOrder是在FPakPlatformFile::Mount(const TCHAR* InPakFilename, uint32 PakOrder, ...)指定的,未指定的话使用最低的优先级0 在进入mount之前,Initialize函数中会按照pak的路径和名字,给这个pak赋一个ReadOrder(即下文中的PakOrder)。 目录优先级 // IPlatformFilePak.cpp bool FPakPlatformFile::Initialize(IPlatformFile* Inner, const TCHAR* CmdLine) { …… #if EXCLUDE_NONPAK_UE_EXTENSIONS && !