1、下载Navicat Premium 16 进入 Navicat Premium官网,选择对应版本下载。
2、Navicat Premium 16安装 双击 navicat161_premium_cs_x64.exe 文件,开始安装。
3、Navicat Premium 16注册 点击下载:NavicatCracker.exe 文件
注意:一定要先断开网络,然后双击 NavicatCracker.exe 文件
在打开的界面中,更改Applied path 为 navicat premium 16的安装路径。
接着点击Pathch!,选择是。
点击Generate!,生成Keygen的值,然后点击copy复制Keygen的值。
双击打开已安装好的navicat,点击注册,输入copy得到的Keygen的值。
点击手动按钮,并将请求码复制到NavicatCracker.exe的Request Code中。
提示如下,代表成功!
利用pom依赖上传jar包到nexus私服 <distributionManagement> <snapshotRepository> <id>nexus-snapshots</id> <name>admin</name> <url>http://url/repository/maven-snapshots/</url> </snapshotRepository> <repository> <id>nexus-releases</id> <name>admin</name> <url>http://url/repository/maven-releases/</url> </repository> </distributionManagement> Settings.xml 如果出现401, unauthorized 那肯定是你私服账号和命名配错了 请确认!!!
大家好,今天和各位分享一下深度学习中常见的标准化方法,在 Transformer 模型中常用的 Layer Normalization,从数学公式的角度复现一下代码。
看本节前建议各位先看一下 Batch Normalization:https://blog.csdn.net/dgvv4/article/details/130567501
Layer Normalization 的论文地址如下:https://arxiv.org/pdf/1607.06450.pdf
1. 原理介绍 深层网络训练时,网络层数的增加会增加模型计算负担,同时也会导致模型变得难以训练。随着网络层数的增加,数据的分布方式也会随着层与层之间的变化而变化,这种现象被称为内部协变量偏移(Internal Convariate Shift, ICS)。这要求模型训练时必须使用较小的学习率,且需要慎重地选择权重初值。ICS 导致训练速度减慢,同时也导致使用饱和的非线性激活函数(如sigmoid,正负两边都会饱和梯度为 0)时出现梯度消失问题。
为解决内部协方差变化(ICS),思路是固定每一层输出的均值和方差,即层归一化算法(Layer Normalization,LN),层归一化算法用每个样本的均值和方差对输入进行归一化。LN 是在单个样本上操作,可以应用于小批次和 RNN。LN 和 BN 有相同的形式,只是不同的归一化方式。
层归一化与批归一化算法的区别只在于统计值的获取方式上,下式是层归一化算法中均值和方差的计算方式,H 表示层的隐藏单元数, 代表第 层中的第 个神经元。
层归一化算法通过计算在一个训练样本上某一层所有的神经元的均值和方差来对输入进行归一化,像批归一化算法那样,同样也给每个神经元加入了增益 和偏置 来实现线性变换,这在归一化后激活函数前使用。
层归一化 LN 和批归一化 BN 不同的是,层归一化在训练和测试时执行同样的计算,由于 LN 与批次大小没有关系,LN 能够在递归神经网络的每个时间步上分别计算归一化操作所需要的均值和方差的值。实验结果表明,层归一化技术相对批归一化技术训练时间更短。
层归一化算法比较适合应用于全连接网络和递归神经网络,有学者尝试在卷积神经网络上采用层归一化算法,但是发现层归一化算法的效果没有批归一化算法好。这是因为对于全连接层,隐藏层中的全部单元对最终预测和重新定位做出相似的贡献,将所有输入缩放到一个图层效果很好。但是,类似贡献的假设在卷积神经网络不再适用,大量的隐藏单位的感受野位于图像边界附近很少被打开,因此来自同一层内其他隐藏单元的统计数据有很大不同。有学者认为认为需要进一步的研究使卷积网络中的层归一化工作取得好的效果。
总体来说,LN 较 BN 简单,它也是通过减少 ICS 来加速神经网络的训练。LN 在训练和测试时没有区别,只需要对当前隐藏层计算均值和方差而不需要保存每层的移动平均和方差用于测试且不受批次大小的限制,可以通过在线学习的方式一条一条的输入训练数据。
优点:批量较小时,效果好;适用于自然语言处理任务。
缺点:批量较大时,效果不如BN。
2. 代码展示 构造一个输入 shape=[B,C,H*W] 的张量,对每个样本在 [C, H*W] 这两个维度上做 LN
import torch from torch import nn class LN(nn.Module): # 初始化 def __init__(self, normalized_shape, # 在哪个维度上做LN eps:float = 1e-5, # 防止分母为0 elementwise_affine:bool = True): # 是否使用可学习的缩放因子和偏移因子 super(LN, self).
OPC UA服务端(Prosys OPC UA Simulation Server) 1.Prosys OPC UA Simulation Server下载地址
https://downloads.prosysopc.com/opc-ua-simulation-server-downloads.php
2.简单使用
2.1 特殊项设置
【1】端口设置
【2】OPC UA Simulation Server运行状态
2.2 新加需要模拟上数的点
2.3 模拟动态变化值,修改ValueType
效果图如下:
2.4 模拟固定值(手动修改值)
OPC UA客户端(Matrikon OPC UA Explorer) 1.Matrikon OPC UA Explorer下载地址
https://www.matrikonopc.com/opc-ua/products/opc-ua-explorer.aspx
2.简单使用
2.1 连接upc ua服务
2.2 查看点位数据的质量情况
1.mysql数据库查询二进制数据 语法: SELECT CONVERT(字段 USING utf8mb4) 别名 FROM 表名
数据库字段类型为blob:
2.postgresql数据库查询二进制数据 语法: select encode(字段,'escape') 别名 FROM 表名
数据库字段类型为bytea:
文章到这里就结束了,有帮助的小伙伴记得点赞收藏加关注呦!!!
使用一个二维数组表示游戏区域
随机生成初始游戏区
检查并标记要消除的区域,移动元素后重新填充空白
import random
# 随机数生成
def get_random_number():
return random.randint(1, 5)
# 创建二维数组
def create_matrix(rows, columns):
return [[get_random_number() for _ in range(columns)] for _ in range(rows)]
# 找到和给定位置相同且相邻的位置
def find_neighbors(x, y, matrix, value):
max_x = len(matrix[0]) - 1
max_y = len(matrix) - 1
neighbors = []
if x > 0 and matrix[y][x - 1] == value:
neighbors.append((x - 1, y))
if x < max_x and matrix[y][x + 1] == value:
文章目录 1 检查用户家目录中的test.sh文件是否存在,并且检查是否有执行权限2 提示用户输入100米赛跑的秒数,要求判断秒数大于0且小于等于10秒的进入选拔赛,大于10秒的都淘汰,如果输入其它字符则提示重新输入;进入选拔赛的成员再进一步判断男女性别,男生进男生组,女生进女生组,如果输入错误请提示错误3 用case语句解压根据后缀名为 .tar.gz 或 .tar.bz2 的压缩包到 /opt 目录4 编写能够自动生成一个6位随机密码的脚本5 输出192.168.80.0/24网段内在线主机的ip地址,统计不在线主机的台数,并把不在线主机的ip地址和不在线时的时间保存到/opt/mywork/ip.txt文件里6 编写能够按照每100行分割文件的脚本7 将一个点分十进制格式的IP地址转换成点分二进制格式,比如 255.255.255.255 ——> 11111111.11111111.11111111.111111118 使用循环语句将一个 0到255 之间的十进制数转换成8位数二进制数9 用户输入密码,脚本判断密码是否正确,正确密码为123456,输入正确提示正确信息,连续输错3次则报警10 求从1到100所有整数的偶数和、奇数和11 提示用户输入一个小于100的整数,并计算从1到该数之间所有整数的和12 计算从1到100所有整数的和13 提示用户输入内容,使用if 语句判断输入的内容是否为整数14 提示用户输入内容,使用if 语句判断输入的内容是否为整数,并判断输入的内容是奇数还是偶数15 用case语句在/etc/init.d/目录中写一个firewalld脚本,并加入到系统服务管理中 1 检查用户家目录中的test.sh文件是否存在,并且检查是否有执行权限 (1) 检查用户家目录中的test.sh文件是否存在,并且检查是否有执行权限.
[root@clr /opt/mywork]# cat 1.sh #!/bin/bash #检查用户家目录中的 test.sh 文件是否存在,并且检查是否有执行权 cd /root test -f test.sh if [ $? -eq 0 ];then test -x test.sh if [ $? -eq 0 ];then echo "有test.sh文件且可执行" else echo "有test.sh文件但不可执行" fi else echo "
nvidia-smi报错:NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver
前提说明:系统是重新通过U盘进行安装的,所以里面几乎是空盘 按照网上教程进行“软件和更新”中安装出现报错:
nvidia-smi报错:NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver
所以参考很多博客,我把我自己的操作流程记录一下,以供参考:
1. 更新软件源
sudo apt-get update 2. 安装所需要依赖,需要安装g++,gcc,make
sudo apt-get install g++ sudo apt-get install gcc sudo apt-get install make 3. 卸载原有NVIDIA驱动
sudo apt-get remove --purge nvidia* 4.禁用nouveau
sudo gedit /etc/modprobe.d/blacklist.conf 在blacklist.conf末尾添加以下两行,保存后关闭文本
blacklist nouveau options nouveau modeset=0 在终端输入如下更新,更新结束后重启电脑
sudo update-initramfs -u 重启后输入如下指令,如无输出则已关闭nouveau
lsmod | grep nouveau 5.
视频转音频
# !/usr/bin/env python # -*-coding:utf-8-*- # date :2023/3/29 14:41 # author:Sabo import os # 林志炫的格式化转换函数 def time_concert_format_of_Terry_lin(input_mp4_name): return input_mp4_name.split("(")[-1].split(")")[0].split(".")[0] # 视频转换音频 ffmpeg格式命令 def video_to_music(input_mp4_name, outpurt_mp3_name, delete_flag): commond = "ffmpeg -i " + input_mp4_name.__str__() + " -vn " + outpurt_mp3_name.__str__() print("commond:", commond) os.system(commond) if delete_flag: os.remove(input_mp4_name) print("{File} removed successfully".format(File = input_mp4_name.split("P")[-1])) # print("commond:", commond) def choose_mp4_file(list_of_video): result_list = [] for i in range(list_of_video.__len__()): if list_of_video[i].split(".")[-1] == "mp4": result_list.append(list_of_video[i]) return result_list def main(origin_site, singer, delete_flag): list_of_video = os.
前言 前段时间去面试了一个公司,成功拿到了offer,薪资也从12k涨到了18k,对于工作都还没两年的我来说,还是比较满意的,毕竟一些工作3、4年的可能还没我高。
我可能就是大家说的卷王,感觉自己年轻,所以从早干到晚,甚至我都想搬张床到工位睡觉了(就是这么卷)。其实也没办法,自己家里条件不是很好,只能靠自己努力点咯!也是希望自己父母不要这么累吧!在大三的时候我就知道自己能干啥,所以从那时候就开始自学软件测试了,大四的时候获得了一个小公司的实习机会。我自己其实并不算个聪明的人,所以只有在工作中去不断的学习、实践,比别人多花一倍甚至几倍的时间,我才能打下扎实的基础,现在工作也是得心应手。
我觉得人还是得逼自己一把,不然你不知道你有多大的潜力!下面我分享一下在面试中问的问题,以及我自己在用的一份《面试笔记》笔记在文末免费领取,这份笔记是我找一位现在在字节工作的学长那里拿的,希望对各位有帮助。
面试经历 一面 1、自我介绍
2、详细讲一下你项目的业务流程
3、公司项目的架构
4、给出一个场景涉及测试用例
5、你是怎么定位分析bug的?
6、说一下做接口自动化的框架
7、你觉得接口自动化最重要的是什么?
8、接口上下文、参数化怎么做的?断言怎么做的?
9、说下unittest框架的特性
10、Linux常用命令?
11、搭过测试环境吗?说下部署的流程?
12、数据库问了两个查询
13、压测是怎么做的?
14、beanshell那些常用的函数
15、压测环境服务器配置
16、jmeter脚本中有断言吗?
17、有没有发现性能上的问题,最后怎么优化的?
18、你有什么想问的吗?
二面 1、自我介绍
2、介绍下公司项目的架构
3、你前公司的业务(问的很详细)
4、你觉得最复杂的一个业务场景
5、http和https的区别测过哪些类型的接口Get,post的区别
6、异步接口有测过吗?怎么测的
7、一个接口发生异常时,你怎么分析
8、性能测试怎么做的,你们主要关注哪位指标
9、有没有发现性能问题,有何优化的(一面也问过)
10、App性能测试有做过吗?
11、数据库索引知道吗,简单说一下
12、left join和inner join的区别?
13、两张表关联,取价格前10的数据
14、python字典和列表谁更快,为什么?
15、python列表怎么去重,多说几种
16、用过init函数吗,说一下作用
17、给你一个排好序的数组,查找某个元素
18、你还有什么想问的吗?
三面(人力面) 1、自我介绍
2、上家公司呆了两年了,为什么想要跳槽
3、同事朋友对你的评价
4、你觉得自己做大的一个缺点在工作上遇到过最有压力的事对前两位面试官的评价
5、对我们公司有了解吗?
6、目前薪资,期望薪资
7、在行业和薪资上,更倾向于?
8、如果给不到你想要的薪资,还会考虑吗?
9、看你是在职状态,最快什么时候能入职
10、你还有什么想问的吗?
面试笔记 我也为大家整理了一套最新的软件测试系统学习教程,包括测试理论、Linux基础、MySQL基础、Web测试、接口测试、App测试、Python基础、Selenium相关、性能测试、LordRunner相关等
一、软件测试基础 软件测试的步骤是什么?
如何录制测试脚本?
应该考虑进行如何测试的测试方法
怎样估计测试工作量?
测试设计的问题
当测试过程发生错误时,有哪几种解决办法?
测试执行的问题
测试评估的目标
如何提高测试?
C/S模式的优点和缺点
1.新建Web项目 2.创建好Web项目后,需要在项目中添加Tomcat的Servlet-api.jar包 方法一:单机File->Project Structure进入Project Structure界面
然后进行如下操作进入到Choose Libraries界面
然后选择Tomcat后点击Add Selected
然后就可以在以下界面看到Tomcat,然后点击OK
最后servlet-api.jar包就导入进来了。 方法二:进入Project Structure界面。单机File->Project Structure
然后这样,进入Select Library Files界面
找到Tomcat目录下的lib目录下的servlet-api.jar导入,点apply,OK
3.创建Servlet类
项目场景: 项目场景:我目前有一个列表,功能可以筛选时间以及渠道,筛选出来的数据包含订单号字段,渲染在列表中,我需要把所有的订单号,根据时间渠道筛选后,把筛选后的所有订单号导出只Excel中。
这个功能一开始也是在网上找办法,但是也是不是很适用,这里就分享一下我的解决方案。
注:这里只提供思路及方法,直接复制就无法使用的,因为涉及到其他的组件(时间,渠道)就没有放全代码了,建议参考一下思路,然后用自己的方法来实现会比复制粘贴更好,授人以鱼不如授人以渔这个道理相信大家都懂。
效果 当点击导出则直接下载对应的数据,这里表头为Hader(可自定义),TrackingNo(必须)为订单号下面的为导出的数据,Startime(必须):开始时间,Endtime(必须):结束时间,LabelType:渠道:当为空时显示空。
1.安装并引入vue-json-excel: 我这里是通过npm的包管理器,并且进行全局引入的方式。
1.下载vue-json-excel npm i vue-json-excel 2.全局引入 在main.js中
//导入导出excel表格组件 import JsonExcel from 'vue-json-excel' Vue.component('downloadExcel', JsonExcel) 2.页面中使用 1.HTML <download-excel class="export-excel-wrapper" :data = "print" :fields = "json_fields" type="csv" header = "Header" name = "filename" style="width:100px;float: left;" > <el-button style="margin-left:20px" type="primary">{{$t('export')}}</el-button> </download-excel> 2.JS export default { data(){ return{ print:[], json_fields:{} } }, methods(){ GetJsonFileds(val){ //导出 let params={ TrackingNo : this.photoinfo.waybill_number, StockID : this.StockInfovalue, LabelType : this.photoinfo.LabelType, Startime : this.
https://www.yuque.com/fuqinzhuxiaocangsang/psnbbh?# 语雀版《广西骚戴软考独家笔记》
最近,一位常年研究股票系统的[开发者] pythonstock 用 Python 写了一个股票分析系统,发布数天就获得了不少关注。
于是我们就推荐给大家,既能学习 python 又能练习炒股。但正如项目作者所说,「本项目只能用于 Python 代码学习,股票分析,投资失败亏钱不负责,不算 BUG。」如果真亏了,我们也不背锅呀,毕竟大家都是韭菜。
pythonstock 的项目页面
总之,分析得准不准先不说,我们先来偷个师,看看这个用 Python 代码进行股票分析的项目到底是怎么实现的吧。
PythonStock:一个用 Python 写成的股票分析系统 根据 GitHub 页面介绍,该项目是基于 Python 的 pandas、tushare、bokeh、[tornado]、stockstats、ta-lib 等框架开发的全栈股票系统。
GitHub 地址:[https://github.com/pythonstock/stock]
它具备以下特点:
1)可以直接使用 docker 本地部署运行,整个项目在 [docker hub]上压缩后仅有 200BM,本地占用 500MB 磁盘空间。
2)使用 Docker 解决 Python 库安装问题,使用 Mariadb(MySQL)存储数据,借助 tushare 抓取数据。
3)使用 [corn]做定时任务,每天进行数据抓取计算,每天 18 点开始进行数据计算,计算当日数据,使用 300 天数据进行计算,大约需要 15 分钟计算完毕。
4)股票数据接口防止被封,按天进行数据缓存,储存最近 3 天数据,每天定时清除,同时使用 read_pickle to_pickle 的 gzip 压缩模式存储。
5)使用 tornado 开发 web 系统,支持股票数据、沪深 300 [成份股]、中证 500 成份股、[龙虎榜数据]、[每日股票]数据、每日大盘指数行情等。
BigInteger类: BigInteger bi1 = new BigInteger("100"); BigInteger bi2 = new BigInteger("50"); // public BigInteger add(BigInteger val):加 System.out.println("add:" + bi1.add(bi2)); // public BigInteger subtract(BigInteger val):减 System.out.println("subtract:" + bi1.subtract(bi2)); // public BigInteger multiply(BigInteger val):乘 System.out.println("multiply:" + bi1.multiply(bi2)); // public BigInteger divide(BigInteger val):除 System.out.println("divide:" + bi1.divide(bi2)); BigDecimal类: BigDecimal bd1 = new BigDecimal("0.09"); BigDecimal bd2 = new BigDecimal("0.01"); // public BigDecimal add(BigDecimal val):加 System.out.println("add:" + bd1.add(bd2)); BigDecimal bd3 = new BigDecimal("1.0"); BigDecimal bd4 = new BigDecimal("
首先在我的项目vue3+vite+antdesign 基础上使用electron,两者并不冲突,只需要在我原先项目基础上安装electron就行,需要安装一些包以及配置就可以了,本次记录一下怎么使用,以及当时遇到的问题
前提是vue3+vite+antdesign 没问题哈!
1.安装包
cnpm i -D concurrently cross-env electron electron-builder electron-packager wait-on
2.配置package.json
注意electron时,"type": "commonjs",用vite项目的时候是"type": "module",(当时这个地方没注意,报错了)
"type": "commonjs",
"scripts": {
"serve": "vite",
"build": "vite build",
"preview": "vite preview",
"start": "electron .",
"packager": "electron-packager ./dist/ --platform=win32 --arch=x64 --overwrite",
"electron": "wait-on tcp:3000 && cross-env IS_DEV=true electron .",
"electron:dev": "concurrently -k \"cross-env BROWSER=none npm run dev\" \"npm run electron\"",
"electron:build.win": "npm run build && electron-builder --win --dir",
"electron:build.linux": "npm run build && electron-builder --linux appImage"
C++ 语法基础一. 变量,输入输出,表达式,和顺序语句标准结构基本类型输入输出常见提交结果1.%5d 每次输出靠右占用五个字符2.%-5d 每次输出靠左占用五个字符3.%05d 每次输出靠右占用五个字符,不足五个以0填充 二. 判断语句1.if语句之后千万不要加分号 (如果加了分号表示if执行了一个空语句)2.其余用法与c语言相同3.逻辑表达式 三. 循环结构(基本和c语言相同)1.while循环:while循环表达式可以嵌入cin等函数, while(cin>>n),因为cin函数是存在返回值的,如果没有返回值是因为读到文件结束符2.reverse函数 四. 数组1.memset2.memcpy 五. 字符串1.字符数组:由若干个字符组成的数组,一种另类的字符串2.字符串:由若干个字符组成3.cin,cout函数本身也是通过地址来读入,打印结果4.fgets(s,n,stdin) 可以读入空格,不会过滤回车5.getline(cin,s) 可以读入空格6.c中string库函数7.标准库函数string(可变长的字符序列,比字符数组更好用)8.substr函数9.stringstream ssin函数10.ssin函数(通常叫ssin,也可以自定义昵称使用)11.sscanf函数back函数 六. 函数(使编代码的过程更加简洁)1.静态变量 static(在函数内部开辟了一个只有该函数所能用的的全局变量)2.参数传递3.inline修饰函数4.函数递归 七. 类,结构体,指针与引用1.类(class)2.结构体(与类的用法相同)3.类与结构体的区别:如果不在内部定义private和public时定义的变量,类默认定义的成员变量属于private,结构体默认定义的成员变量属于public4.类与结构体可以在内部构造函数5.指针6.引用7.链表8.链表遍历9.条件表达式的一种应用 八. STL1.vector 第八章 C++ STL1.#include <vector>2.#include <queue>3.#include <stack>4.#include <deque>5.#include <set> 语法基础 一. 变量,输入输出,表达式,和顺序语句 标准结构 #include <iostream> using namespace std; int main() { cout<<"Hello World"<<endl; return 0; } using namespace std;用于创建命名空间,cout和cin都属于其中
基本类型 (1) 布尔型 存储true和flase 1byte
(2) 字符型 char 1byte
(3) 整型 int 4byte
(4) 浮点型 实数和科学计数法
在解锁小米6的时候,有一个大坑,就是卡在当前未连接手机;
错误的启动/连接方式截图:
正确的启动FASTBOOT截图:
错误的原因在于启动方式不是音量+和电源键,而是音量-和电源键,虽然软件中是写的是音量下+电源键,但谁会这么写呢,一般都是音量加(+),音量减(-)对吧?
而且错误的启动方式居然也可以连接电脑,实在是无语;
另外也可通过adb reboot bootloader启动到FASTBOOT模式;
Mybatis中一级缓存 和 二级缓存的区别 两者区别:一级缓存的作用域是在SqlSession中,二级缓存的作用域是针对mapper做缓存。
一级缓存(本地缓存) 一级缓存是框架默认为我们开启的,我们不需要做任何配置。
例如我们首次查询id为1的用户,mybatis会将该用户的对象存储在一级缓存中;
如果在此中间 sqlSession 执行了commit操作(增删改) ,则mybatis会清空一级缓存的数据 ,这样就能让我们的数据是最新的,避免产生脏读。
当我们再次查 id 为 1 的用户时,mybatis就会去缓存中查找,就不需要再从数据库中去查询。
mybatis一级缓存是默认开启的,是SqlSession级别的缓存,在操作数据库的时候需要创建一个SqlSession,其中有一个HashMap,用于存储缓存数据。不同的SqlSession之间,其缓存数据的HashMap是不同的;
所以当我们多次调用同一个Mapper和同一个方法的同一个参数,只会进行一次数据库查询,然后把数据缓存到缓冲中,以后直接先从缓存中取出数据,不会直接去查数据库。但是不同的SqlSession对象,因为不同的SqlSession都是相互隔离的,所以相同的Mapper、参数和方法,他还是会再次发送到SQL到数据库去执行,返回结果。所以我们需要根据需求开启二级缓存
二级缓存(全局缓存) 二级缓存是 mapper 级别的缓存,多个sqlSession去操作同一个Mapper的sql,不管Sqlsession 是否相同,只要 mapper 的 namespace相同就能共享数据。也可以称之为 namespace 级别的缓存 。
sqlSession 关闭后(close) ,一级缓存的数据会保存到二级缓存中,新的相同的查询语句就会去二级缓存中去查询。
二级缓存是Mapper级别的缓存,多个SqlSession去操作同一个Mapper中的SQL语句,则这些SqlSession可以共享二级缓存,即二级缓存是跨SqlSession的。
二级缓存开启 1,xml 配置中开启 二级缓存
<settings> <!-- 开启二级缓存(默认是开的,这里写出来是为了方便代码维护) --> <setting name="cacheEnabled" value="true" /> </settings> 2,去mapper映射文件中使用二级缓存
<!-- 开启本mapper所在namespace的二级缓存 --> <cache /> 3,需要将要存储数据的 pojo 实现 Serializable接口,为了将数据取出做反序列化操作, 因为二级的缓存的存储方式多种多样,有可能存储在内存中,也可能储存到磁盘中。如果我们要再取这个缓存的话,就需要反序列化了。所以建议mybatis中的pojo都去实现Serializable接口。
mybatis解读 1、开启缓存的弊端是数据没有实时性,当数据库中的数据一旦修改,查询的数据还是缓存中的数据没有实时性,对于某些需要实时性显示数据的接口我们可以设置 useCache=“false” ,设置该属性后,该接口每次查询出来都是去执行sql查询出实时性数据。如:
<select id="findArtPageview" parameterType="com.Article" resultType="int" useCache="false"> select pageview from article where aid=#{aid} </select> 设置useCache=false可以禁用当前select语句的二级缓存,即每次查询都会发出sql去查询,默认情况是true,即该sql使用二级缓存。所以:针对每次查询都需要最新的数据sql,要设置成useCache=false,禁用二级缓存。
删除前
删除后
index.js
const { server } = require('./server/index') const { connectDB } = require("./db/index.js") const Model = require("./model/user") // 连接mongodb数据库 connectDB().then(res => { }) // 监听请求 server.on('request', async function (req, res) { const { method, url, } = req if (method === 'GET') { if (url === '/user') { // 查找集合中的数据(user) const data = await Model.find(); res.end(JSON.stringify({ code: 0, data: { list: data || [] } })) } } else if (method === 'DELETE') { if (url === '/user') { // 查找集合中的数据(user) const data = await Model.
目录
1、printf()函数
1.1、printf()函数中的标记
1.2、输出最小宽度(width)
1.3、精度(.precision)
2、scanf()函数
2.1、scanf(“输入控制符”, 输入参数)
2.2、scanf(“输入控制符非输入控制符”, 输入参数);
2.3、字符串和转义字符
2.4、注意事项
1、printf()函数 printf()函数是C语言标准输出函数,用于将格式化后的字符串输出到标准输出(对应终端的屏幕)。使用printf函数需要声明在头文件#include<stdio.h>下。
认识一个函数先了解它的原型
int printf ( const char * format, ... ); 返回值:正确返回输出的字符总数,错误返回负值。
那怎么调用printf()函数呢?调用格式:
printf("格式化字符串", 输出表列) 格式化字符串包含三种对象,分别为:
(1)字符串常量;
(2)格式控制字符串;
(3)转义字符。
字符串常量原样输出,在显示中起提示作用。输出表列中给出了各个输出项,要求格式控制字符串和各输出项在数量和类型上应该一一对应。其中格式控制字符串是以 % 开头的字符串,在 % 后面跟有各种格式控制符,以说明输出数据的类型、宽度、精度等。后面将详细介绍字符串。
printf() 的格式控制字符串组成如下:
%[flags][width][.prec][length]type
%[标志][最小宽度][.精度][类型长度]类型
上面五个选项中,类型是必不可少的,type用于规定输出数据的的类型。下表列出一些转换说明和各自对应的输出类型。
转换说明及其打印结果 转换说明输出示例%a浮点数、十六进制数和p记数法 (C99/C11)printf("%a",3.14);输出0x1.91eb851eb851fp+1 %A
浮点数、十六进制数和p记数法 (C99/C11)printf("%A",3.14);输出0X1.91EB851EB851FP+1%c单个字符printf("%c",a);输出字符a%d有符号十进制整数printf("%d",10);输出十进制数字10%e浮点数,e记数法printf("%e",3.14e10);输出3.140000e+10%E浮点数,e 记数法printf("%E",3.14e10);输出3.140000E+10%f浮点数,十进制记数法printf("%f",3.14);输出浮点数3.14%g根据值的不同,自动选择%f 或%e。%e 格式用于指数小于-4 或者大于或等于精度时 printf("%g",0.00000123);输出1.23e-07
printf("%g",0.123);输出0.123
%G根据值的不同,自动选择%f 或%E。%E 格式用于指数小于-4 或者大于或等于精度时 printf("%G",0.00000123);输出1.23E-07
printf("%G",0.123);输出0.123
%i有符号十进制整数(与%d 相同)printf("%i",123);输出123%o无符号八进制整数printf("%o",12);输出14%p指针printf("%p","hello");输出00B07B30%s字符串printf("%s","hello");输出hello%u无符号十进制整数printf("%u",123);输出123%x无符号十六进制整数,使用十六进制数 0fprintf("%x",123);输出0x7b%X无符号十六进制整数,使用十六进制数 0Fprintf("%X",123);输出0x7B%%打印一个百分号printf("%%");输出% 其中有一些我们在之前就有接触过(%d,%c,%u等等),这里并不是全部,但以上这些是比较常用的,希望读者可以多加练习从而记住。
1.1、printf()函数中的标记 printf()函数的标记 标记含义-待打印项左对齐。即,从字段的左侧开始打印该项项+有符号值若为正,则在值前面显示加号:若为负,则在值前面显示减号空格有符号值若为正,则在值前面显示前导空格(不显示任何符号): 若为负,则在值前面显示减号+标记覆盖一个空格#把结果转换为另一种形式。如果是%o格式,则以0开始: 如果是%x或X格式,则以0x或 0X开始:对于所有的浮点格式,#保证了即使后面没有任何数字,也打印一个小数点字符。对于%q 和%G 格式,#防止结果后面的 0被删除0对于数值格式,用前导0代替空格填充字段宽度。对于整数格式,如果出现-标记或指定精度,则忽略该标记 这里附上我当时学习的代码和运行截图:
❤️觉得内容不错的话,欢迎点赞收藏加关注😊😊😊,后续会继续输入更多优质内容❤️ 👉有问题欢迎大家加关注私戳或者评论(包括但不限于NLP算法相关,linux学习相关,读研读博相关......)👈 (封面图由文心一格生成) 文本的清洗和标准化:如何处理混乱的数据? 在现代社会,我们每天都处理大量的文本数据。然而,这些数据常常是混乱的、不一致的,包含着各种各样的错误和噪声。如果我们想要从这些数据中提取有用的信息,首先需要进行文本的标准化和清洗。
本文将详细介绍文本的标准化和清洗的原理,并结合代码进行讲解,帮助读者更好地理解如何处理混乱的文本数据。
1. 文本的标准化 文本的标准化是指将不同格式、不同来源的文本数据转化为统一的格式和标准。这个过程可以包括以下几个方面:
1.1 字符集的转换 在不同的计算机系统中,字符集的编码方式可能不同。为了确保文本的一致性和可读性,我们需要将不同编码方式的字符转换为相同的编码方式。在 Python 中,我们可以使用 encode() 和 decode() 方法实现字符集的转换。
1.2.单词的统一化 文本数据中常常包含各种形式的单词,包括大小写不同、缩写形式、不同时态等。为了方便文本的处理和分析,我们需要将这些不同形式的单词转化为统一的形式。在 Python 中,我们可以使用 lower() 方法将所有单词转化为小写形式,或者使用正则表达式进行更为复杂的处理。
1.3 标点符号和特殊字符的处理 文本中常常包含各种标点符号和特殊字符,如逗号、句号、换行符等。这些字符在文本分析和处理中通常是无用的,需要被删除或替换为特定的符号。在 Python 中,我们可以使用 replace() 和正则表达式来实现这个过程。
1.4 时间和日期的统一化 在一些文本数据中,可能包含时间和日期的信息,如 2022 年 5 月 6 日或 2022-05-06。为了方便时间的处理和比较,我们需要将这些时间信息转化为统一的格式,如 ISO 格式。在 Python 中,我们可以使用 datetime 模块来实现时间和日期的处理。
2. 文本的清洗 文本的清洗是指通过删除无用的信息、修复错误和噪声等方式,将文本数据变得更加整洁和规范。这个过程可以包括以下几个方面:
2.1 去除 HTML 标签和特殊字符 在一些文本数据中,可能包含 HTML 标签和特殊字符,如 <、>等。这些标签和字符在文本分析和处理中是无用的,需要被删除或替换为特定的符号。在 Python 中,我们可以使用第三方库,如 Beautiful Soup 和 lxml,来去除 HTML 标签。而对于特殊字符,我们可以使用 replace() 方法或正则表达式来替换。
2.2 删除停用词 停用词是指在文本中频繁出现但不具有实际意义的单词,如“的”、“了”等。这些单词会占用计算资源,降低文本处理的效率,因此需要被删除。在 Python 中,我们可以使用第三方库,如 NLTK 和 spaCy,来删除停用词。
本人发现在使用 PHP 开发公众号时,有时候会遇到无法通过微信公众号平台验证的问题,这在开发过程中是很常见的一个问题。本文将会介绍该问题的可能原因以及解决方法,帮助 PHP 开发者解决公众号验证失败问题。 一、问题描述 当开发者在微信公众平台上填写好服务器地址,在点击“提交”按钮后,微信平台验证失败,提示“token验证失败”或“URL不正确,无法通过验证”。
二、问题原因 (一)URL 格式不正确
在微信公众平台中,输入的 URL 必须以“http”或“https”开头,并且需要携带端口号(如果有的话)。如果 URL 不正确,则会无法通过微信的验证。
(二)Token 不正确或未传递
Token 是公众号用来验证开发者身份的重要参数,在服务器中也需要使用到。如果 Token 在填写过程中输入错误、被恶意篡改或者未正常传递到服务器中,则导致无法进行验证。
(三)服务器响应头信息不正确
在在微信公众平台验证时,会访问开发者填写的 URL,并检测其响应头信息是否正确。在 HTTP 响应头信息中,Content-Type 必须为”text/plain”,并且不能设置 Content-Length 以及 Transfer-Encoding:chunked。如果服务器返回的响应头信息不正确,则可能导致验证失败。
(四)防火墙设置
在某些情况下,防火墙可能会阻止微信服务器与开发者服务器之间的互通,导致无法通过验证。此时需要检查防火墙设置,并将流量放行。
三、解决方案 如果您遇到了 PHP 公众号验证失败问题,可以尝试下面的解决方案。
(一)检查 URL 是否正确
在填写服务器地址时,需要注意 URL 格式是否正确。格式应为“http://www.example.com”,并且需要携带端口号。如果您使用了 HTTPS,则需要将 URL 开头的“http”改为“https”。
(二)检查 Token 是否正确或未传递
检查 Token 是否正确或者是否未正常传递到服务器中。可以通过打印调试信息来确定 Token 是否已经正常获取。同时,注意在 Token 的生成和传递过程中,如遇特殊字符,需要先进行 URL 编码。
(三)检查服务器响应头信息是否正确
在服务器中,需要将 Content-Type 设置为”text/plain”。同时不应该设置 Content-Length 或 Transfer-Encoding:chunked。检查一下是否遵守了这些要求。
(四)检查防火墙设置
如果问题依旧存在,尝试检查防火墙设置是否存在问题。如果使用云服务器,则需要查看相关安全组设置,并将与微信服务器的交互流量放行。
四、总结 本文介绍了 PHP 公众号验证失败问题的原因及解决方案。无法通过微信公众号验证是 PHP 开发过程中会经常遇到的问题,但是只要知道了问题的原因,就能够针对性地解决。在开发微信公众号的过程中,还需要注意对 Token 的安全性进行保护,并保证服务器的响应头信息和 URL 格式正确。
来源:机器学习算法那些事 极市平台
https://zhuanlan.zhihu.com/p/136521625
本文约6000字,建议阅读10分钟
本篇文章将从一个更直观的角度对当前经典流行的GNN网络,包括GCN、GraphSAGE、GAT、GAE以及graph pooling策略DiffPool等等做一个简单的小结。
“近年来,深度学习领域关于图神经网络(Graph Neural Networks,GNN)的研究热情日益高涨,图神经网络已经成为各大深度学习顶会的研究热点。GNN处理非结构化数据时的出色能力使其在网络数据分析、推荐系统、物理建模、自然语言处理和图上的组合优化问题方面都取得了新的突破。”
图神经网络有很多比较好的综述[1][2][3]可以参考,更多的论文可以参考清华大学整理的GNN paper list[4] 。本篇文章将从一个更直观的角度对当前经典流行的GNN网络,包括GCN、GraphSAGE、GAT、GAE以及graph pooling策略DiffPool等等做一个简单的小结。笔者注:行文如有错误或者表述不当之处,还望批评指正!
一、为什么需要图神经网络? 随着机器学习、深度学习的发展,语音、图像、自然语言处理逐渐取得了很大的突破,然而语音、图像、文本都是很简单的序列或者网格数据,是很结构化的数据,深度学习很善于处理该种类型的数据(图1)。
图1
然而现实世界中并不是所有的事物都可以表示成一个序列或者一个网格,例如社交网络、知识图谱、复杂的文件系统等(图2),也就是说很多事物都是非结构化的。
图2
相比于简单的文本和图像,这种网络类型的非结构化的数据非常复杂,处理它的难点包括:
图的大小是任意的,图的拓扑结构复杂,没有像图像一样的空间局部性;
图没有固定的节点顺序,或者说没有一个参考节点;
图经常是动态图,而且包含多模态的特征。
那么对于这类数据我们该如何建模呢?能否将深度学习进行扩展使得能够建模该类数据呢?这些问题促使了图神经网络的出现与发展。
二、图神经网络是什么样子的? 相比较于神经网络最基本的网络结构全连接层(MLP),特征矩阵乘以权重矩阵,图神经网络多了一个邻接矩阵。计算形式很简单,三个矩阵相乘再加上一个非线性变换(图3)。
图3
因此一个比较常见的图神经网络的应用模式如下图(图4),输入是一个图,经过多层图卷积等各种操作以及激活函数,最终得到各个节点的表示,以便于进行节点分类、链接预测、图与子图的生成等等任务。
图4
上面是一个对图神经网络比较简单直观的感受与理解,实际其背后的原理逻辑还是比较复杂的,这个后面再慢慢细说,接下来将以几个经典的GNN models为线来介绍图神经网络的发展历程。
三、图神经网络的几个经典模型与发展 1 . Graph Convolution Networks(GCN)[5]
GCN可谓是图神经网络的“开山之作”,它首次将图像处理中的卷积操作简单的用到图结构数据处理中来,并且给出了具体的推导,这里面涉及到复杂的谱图理论,具体推到可以参考[6][7]。推导过程还是比较复杂的,然而最后的结果却非常简单( 图5)。
图5
我们来看一下这个式子,天呐,这不就是聚合邻居节点的特征然后做一个线性变换吗?没错,确实是这样,同时为了使得GCN能够捕捉到K-hop的邻居节点的信息,作者还堆叠多层GCN layers,如堆叠K层有:
上述式子还可以使用矩阵形式表示如下,
其中 是归一化之后的邻接矩阵, 相当于给 层的所有节点的embedding做了一次线性变换,左乘以邻接矩阵表示对每个节点来说,该节点的特征表示为邻居节点特征相加之后的结果。(注意将 换成矩阵 就是图3所说的三矩阵相乘)
那么GCN的效果如何呢?作者将GCN放到节点分类任务上,分别在Citeseer、Cora、Pubmed、NELL等数据集上进行实验,相比于传统方法提升还是很显著的,这很有可能是得益于GCN善于编码图的结构信息,能够学习到更好的节点表示。
图6
当然,其实GCN的缺点也是很显然易见的,第一,GCN需要将整个图放到内存和显存,这将非常耗内存和显存,处理不了大图;第二,GCN在训练时需要知道整个图的结构信息(包括待预测的节点), 这在现实某些任务中也不能实现(比如用今天训练的图模型预测明天的数据,那么明天的节点是拿不到的)。
2. Graph Sample and Aggregate(GraphSAGE)[8]
为了解决GCN的两个缺点问题,GraphSAGE被提了出来。在介绍GraphSAGE之前,先介绍一下Inductive learning和Transductive learning。注意到图数据和其他类型数据的不同,图数据中的每一个节点可以通过边的关系利用其他节点的信息。这就导致一个问题,GCN输入了整个图,训练节点收集邻居节点信息的时候,用到了测试和验证集的样本,我们把这个称为Transductive learning。然而,我们所处理的大多数的机器学习问题都是Inductive learning,因为我们刻意的将样本集分为训练/验证/测试,并且训练的时候只用训练样本。这样对图来说有个好处,可以处理图中新来的节点,可以利用已知节点的信息为未知节点生成embedding,GraphSAGE就是这么干的。
GraphSAGE是一个Inductive Learning框架,具体实现中,训练时它仅仅保留训练样本到训练样本的边,然后包含Sample和Aggregate两大步骤,Sample是指如何对邻居的个数进行采样,Aggregate是指拿到邻居节点的embedding之后如何汇聚这些embedding以更新自己的embedding信息。下图展示了GraphSAGE学习的一个过程:
图7
第一步,对邻居采样;
第二步,采样后的邻居embedding传到节点上来,并使用一个聚合函数聚合这些邻居信息以更新节点的embedding;
第三步,根据更新后的embedding预测节点的标签。
一个vue的页面一般是由多个组件构成的,接下来将讲讲vue如何引入组件
文章 组件存放全局注册使用 局部注册 组件存放 在开发大型项目时:
公共组件存放在component中页面组件存放在当前页面的文件夹中(或者同级文件夹中) 全局注册 例如引入TopHeader顶部导航栏组件
在main.js中添加如下代码:
import TopHeader from "@/component/TopHeader" //全局组件挂载 Vue.component('TopHeader',TopHeader)//其中'TopHeader'为组件的名字 使用 当使用首字母大写命名定义组件时,在引用组件时可以使用以下两种写法
当使用短横线分割命名定义组件时,在引用组件时只能使用第二种写法
//写法一: <TopHeader></TopHeader> //写法二: <top-header></top-header> 注意!组件内部要定义name
局部注册 例如引入TopHeader顶部导航栏组件
在想要引入组件的vue文件中添加如下代码:
import TopHeader from "@/src/views/common/TopHeader" export default{ //写法一: components:{ 'TopHeader':TopHeader//引号中可以设置组件名 } //写法二: components:{ TopHeader } } //写法三:() export default{ components:{ TopHeader:() => import("@/src/views/common/TopHeader") } }
<ListItem @click="showModal(item)"> <ListItemMeta> <template #title> <span @click.stop> <Checkbox v-model="item.checked" @change="change(item)" /> </span> <a-button class="ml-2" type="link">{{ item.title }}</a-button> <!-- </Badge> --> </template> <template #description> <div class="zw_content" v-html="item.zw"></div> <span style="color: #222">发送人:{{ item.name }}</span> <span class="pl-2" style="color: #222">接收时间:{{ item.time }}</span> </template> </ListItemMeta> </ListItem>``` 在这个代码中checkbox的change事件会触发最顶层的ListItem的点击事件,为了阻止事件冒泡,但是给@change加.stop是不生效的,所以解决思路是给checkbox加一个小的父组件,由此checkbox的@change事件会先出发父组件span的点击事件,然后给span的点击事件加上.stop就成功阻止了顶层的事件冒泡
即席查询调研报告 什么是即席查询 即席查询(Ad Hoc)是用户根据自己的需求,灵活的选择查询条件,系统能够根据用户的选择生成相应的统计报表。即席查询与普通应用查询最大的不同是普通的应用查询是定制开发的,而即席查询是指那些用户在使用系统时,根据自己当时的需求自定义的查询。
测试组件介绍 Apache Doris 是一个现代化的MPP分析型数据库产品。仅需亚秒级响应时间即可获得查询结果,有效地支持实时数据分析。支持数据实时导入和实时查询,并且可以支持10PB以上的超大数据集。提供 OLAP 数据分析。(同时支持聚合和明细查询分析)
starRocks fork于 Apache Doris,在此基础上做了一些增强
特性
1、联邦查询
StarRocks支持使用外表的方式进行联邦查询,当前可以支持Hive,MySQL,Elasticserach三种类型的外表,用户无需通过数据导入,可以直接进行数据查询加速。
2、全面向量化引擎
CPU需要支持AVX2指令集, cat /proc/cpuinfo |grep avx2有结果输出表明CPU支持,如果没有支持,建议更换机器,StarRocks使用向量化技术需要一定的指令集支持才能发挥效果。
3、智能查询优化
StarRocks通过CBO优化器(Cost Based Optimizer)可以对复杂查询自动优化。无需人工干预,就可以通过统计信息合理估算执行成本,生成更优的执行计划,大大提高了Adhoc和ETL场景的数据分析效率。
4、智能物化视图
StarRocks支持智能的物化视图。用户可以通过创建物化视图,预先计算生成预聚合表用于加速聚合类查询请求。
StarRocks的物化视图能够在数据导入时自动完成汇聚,与原始表数据保持一致。并且在查询的时候,用户无需指定物化视图,StarRocks能够自动选择最优的物化视图来满足查询请求。
5、标准SQL
StarRocks支持标准的SQL语法,包括聚合,JOIN,排序,窗口函数,自定义函数等功能。StarRocks可以完整支持TPC-H的22个SQL和TPC-DS的99个SQL。此外,StarRocks还兼容MySQL协议语法,可使用现有 的各种客户端工具、BI软件访问StarRocks,
对StarRocks中的数据进行拖拽式分析。
6、流批一体
StarRocks支持实时和批量两种数据导入方式,支持的数据源有Kafka, HDFS, 本地文件,支持的数据格式有ORC, Parquet和CSV等,StarRocks可以实时消费Kafka数据来完成数据导入,保证数据不丢不重(exactly once)。StarRocks也可以从本地或者远程(HDFS)批量导入数据。
Presto Presto是一个分布式SQL查询引擎, 它被设计为用来专门进行高速、实时的数据分析。它支持标准的ANSI SQL,包括复杂查询、聚合(aggregation)、连接(join)和窗口函数(window functions),动态编译/利用cpu的指令集并行化执行。它的产生是为了解决hive的MR太慢的问题,Presto 本身并不存储数据,但是可以接入多种数据源,并且支持跨数据源的级联查询。Presto是一个OLAP的工具,擅长对海量数据进行复杂的分析。
ClickHouse Clickhouse由俄罗斯yandex公司开发。是一款用于大数据实时分析的列式数据库管理系统。通过向量化的执行以及对cpu底层指令集的使用,可以对海量数据进行并行处理,从而加快数据的处理速度。
除此之外,adhoc还有Impala,但经社区反馈其多表查询性能和presto差不多,但是单表查询方面却不如presto好。而且Impala有很多不支持的地方,例如:不支持Date数据类型,不支持ORC文件格式等等,需要采用parquet格式进行查询,而且Impala在查询时占用的内存很大。因此直接pass掉
测试方法 TPC-H基准压测
TPC-H 基准测试是由TPC-D发展而来的,是面向商品零售业的决策支持系统测试基准,它定义了8张表,22个查询,遵循SQL92;基准的数据库模式遵循第三范式;新兴的数据仓库开始采用新的模型,如星型模型、雪花模型。
表的信息:2个事实表:lineorder,orders 6个维度表:customer,part,parsupp,supplier,region,nation
数据查询:22条标准SQL查询测试语句:统计查询、多表关联、sum、复杂条件、group by、order by等组合方式
TPC-H基准sql
SSB基准压测
SSB(Star Schema Benchmark)是在TPC-H基础之上,麻省州立大学波士顿校区的研究人员定义的基于现实商业应用的数据模型,是学术界和工业界广泛使用的一个星型模型测试集(来源论文),比较公正和中立。
表的信息:1张大宽表:lineorder_flat;1张事实表:lineorder4张维度表:customer,part,dates,supplier
数据查询:2类查询场景(单表和多表join)每类场景下有13条标准SQL查询测试语句:统计查询、多表关联、sum、复杂条件、group by、order by等组合方式
本次主要通过ssb基准进行测试,通过这个测试集合可以方便的对比各种OLAP产品的基础性能指标。Clickhouse 通过改写SSB,将星型模型打平转化成宽表,改造成了一个单表测试benchmark。本报告记进行了StarRocks、ApacheDoris和Clickhouse在SSB单表测试,以及StarRocks和ApacheDoris的多表测试,由于Clickhouse对多表Join支持有限,这也不是clickhouse的强项,所以在多表测试中并未将Clickhouse加入测试。
创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡>𖥦<)!!
主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步!
给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ
c语言系列专栏:c语言重点之路整合
字符串知识点:字符串基本概念、存储原理
字符串输出目录 一、字符串输出二、对%s 仿真声明:1.下标方式输出定义:2.指针方式输出定义:调用测试:运行结果: 一、字符串输出 输出:
定义一个字符串然后通过%s格式输出字符串名称就可以打印出字符串的内容
二、对%s 仿真 字符串常用于文字处理,常用且实用。因此其常用功能被封装成了一套API。可通过string.h进行使用。
通过仿真我们可以理解其函数内部工作机制的细节
定义一个函数,传入字符串名称就可以打印出该字符串的内容
再次使用%c而不用%s输出字符串
声明: void prints(char str[ ]); 1.下标方式输出定义: void prints(char str[]) { //下标方式 for (int i = 0; str[i] != '\0';i++) { printf("%c", str[i]); } } 2.指针方式输出定义: void prints(char str[]) { //指针方式 while (*str != '\0') //也可以改为while (*str) 因为到结束语'\0'时会退出循环 { printf("
目录 操作数据库
创建数据库
查看数据库
选择数据库
删除数据库
操作数据表
创建表
修改表
查看表
删除表
1.操作数据库 1.1创建数据库 MySQL中创建数据库的基本SQL语法格式如下:
语法
CREATE DATABASE 数据库名称; 在MySQL中,以英文半角分好(;)作为一条命令的结束符,且在Windows系统下,默认不区分大小写.
提示:
通过执行SQL语句的结果发现,下面有几行提示:
1、第一行表示执行的命令
2、第二行表示执行的结果,OK或受影响表示成功。
3、第三行表示执行时间
1.2 查看数据库 执行查看数据库命令可以查看已经存在的数据库表。
语法:
SHOW DATABASES; 执行结果如下:
从结果发现,执行该语句之后,会显示一个列表,该列表除了有新建的数据库之外,还有别的数据库。
1.3 选择数据库 数据是存在数据库表中的,在对数据进行操作之前,想要确定该表所以的数据库,因此需要选择一个数据库。
语法:
USE 数据库名称; 从结果中可以看出,如果选择的数据库不存在则会报错,如果存在且用户有权限访问,我这里提示受影响,有的是提示OK,即数据库已经切换。
1.4 删除数据库 语法:
DROP DATABASE 数据库名称; 2.操作数据表 2.1创建表 创建数据库表的步骤如下:
(1)确定表中有哪些字段
(2)确定每个字段的数据类型
(3)给表添加各种约束
在确定了数据库之后,可以使用SQL语句创建表结构。
创建表语法如下:
CREATE TABLE [IF NOT EXISTS] table_name( # IF NOT EXISTS是判断表存不存在,防止报错 字段1 数据类型[字段属性,约束], 字段2 数据类型[字段属性,约束], 字段3 数据类型[字段属性,约束] )[表类型][表字符集][注释]; 注意:
作者:王斌 谢春宇 冷大炜
引言
目标检测是计算机视觉中的一个非常重要的基础任务,与常见的的图像分类/识别任务不同,目标检测需要模型在给出目标的类别之上,进一步给出目标的位置和大小信息,在CV三大任务(识别、检测、分割)中处于承上启下的关键地位。当前大火的多模态GPT4在视觉能力上只具备目标识别的能力,还无法完成更高难度的目标检测任务。而识别出图像或视频中物体的类别、位置和大小信息,是现实生产中众多人工智能应用的关键,例如自动驾驶中的行人车辆识别、安防监控应用中的人脸锁定、医学图像分析中的肿瘤定位等等。
已有的目标检测方法如YOLO系列、R-CNN系列等耳熟能详的目标检测算法在科研人员的不断努力下已经具备很高的目标检测精度与效率,但由于现有方法需要在模型训练前就定义好待检测目标的集合(闭集),导致它们无法检测训练集合之外的目标,比如一个被训练用于检测人脸的模型就不能用于检测车辆;另外,现有方法高度依赖人工标注的数据,当需要增加或者修改待检测的目标类别时,一方面需要对训练数据进行重新标注,另一方面需要对模型进行重新训练,既费时又费力。一个可能的解决方案是,收集海量的图像,并人工标注Box信息与语义信息,但这将需要极高的标注成本,而且使用海量数据对检测模型进行训练也对科研工作者提出了严峻的挑战,如数据的长尾分布问题与人工标注的质量不稳定等因素都将影响检测模型的性能表现。
发表于CVPR2021的文章OVR-CNN[1]提出了一种全新的目标检测范式:开放词集目标检测(Open-Vocabulary Detection,OVD,亦称为开放世界目标检测),来应对上文提到的问题,即面向开放世界未知物体的检测场景。OVD由于能够在无需人工扩充标注数据量的情形下识别并定位任意数量和类别目标的能力,自提出后吸引了学术界与工业界持续增长的关注,也为经典的目标检测任务带来了新的活力与新的挑战,有望成为目标检测的未来新范式。具体地,OVD技术不需要人工标注海量的图片来增强检测模型对未知类别的检测能力,而是通过将具有良好泛化性的无类别(class-agnostic)区域检测器与经过海量无标注数据训练的跨模态模型相结合,通过图像区域特征与待检测目标的描述性文字进行跨模态对齐来扩展目标检测模型对开放世界目标的理解能力。跨模态和多模态大模型工作近期的发展非常迅速,如CLIP[2]、ALIGN[3]与R2D2[4]等,而它们的发展也促进了OVD的诞生与OVD领域相关工作的快速迭代与进化。
OVD技术涉及两大关键问题的解决:1)如何提升区域(Region)信息与跨模态大模型之间的适配;2)如何提升泛类别目标检测器对新类别的泛化能力。从这个两个角度出发,下文我们将详细介绍一些OVD领域的相关工作。
OVD基本流程示意[1]
OVD的基础概念:OVD的使用主要涉及到 few-shot 和 zero-shot两大类场景,few-shot是指有少量人工标注训练样本的目标类别,zero-shot则是指不存在任何人工标注训练样本的目标类别。在常用的学术评测数据集COCO、LVIS上,数据集会被划分为Base类和Novel类,其中Base类对应few-shot场景,Novel类对应zero-shot场景。如COCO数据集包含65种类别,常用的评测设定是Base集包含48种类别,few-shot训练中只使用该48个类别。Novel集包含17种类别,在训练时完全不可见。测试指标主要参考Novel类的AP50数值进行比较。
论文地址:https://arxiv.org/pdf/2011.10678.pdf
代码地址:https://github.com/alirezazareian/ovr-cnn
OVR-CNN是CVPR2021的Oral-Paper,也是OVD领域的开山之作。它的二阶段训练范式,影响了后续很多的OVD工作。如下图所示,第一阶段主要使用image-caption pairs对视觉编码器进行预训练,其中借助BERT(参数固定)来生成词掩码,并与加载ImageNet预训练权重的ResNet50进行弱监督的Grounding匹配,作者认为弱监督会让匹配陷入局部最优,于是加入多模态Transformer进行词掩码预测来增加鲁棒性。
第二阶段的训练流程与Faster-RCNN类似,区别点在于,特征提取的Backbone来自于第一阶段预训练得到的ResNet50的1-3层,RPN后依然使用ResNet50的第四层进行特征加工,随后将特征分别用于Box回归与分类预测。分类预测是OVD任务区别于常规检测的关键标志,OVR-CNN中将特征输入一阶段训练得到的V2L模块(参数固定的图向量转词向量模块)得到一个图文向量,随后与标签词向量组进行匹配,对类别进行预测。在二阶段训练中,主要使用Base类对检测器模型进行框回归训练与类别匹配训练。由于V2L模块始终固定,配合目标检测模型定位能力向新类别迁移,使得检测模型能够识别并定位到全新类别的目标。
如下图所示,OVR-CNN在COCO数据集上的表现远超之前的Zero-shot目标检测算法。
论文地址:https://arxiv.org/abs/2112.09106
代码地址:https://github.com/microsoft/RegionCLIP
OVR-CNN中使用BERT与多模态Transfomer进行image-text pairs预训练,但随着跨模态大模型研究的兴起,科研工作者开始利用CLIP,ALIGN等更强力的跨模态大模型对OVD任务进行训练。检测器模型本身主要针对Proposals,即区域信息进行分类识别,发表于CVPR2022的RegionCLIP[5]发现当前已有的大模型,如CLIP,对裁剪区域的分类能力远低于对原图本身的分类能力,为了改进这一点,RegionCLIP提出了一个全新的两阶段OVD方案。
第一阶段,数据集主要使用CC3M,COCO-caption等图文匹配数据集进行区域级别的蒸馏预训练。具体地,
1.将原先存在于长文本中的词汇进行提取,组成Concept Pool,进一步形成一组关于Region的简单描述,用于训练。
2.利用基于LVIS预训练的RPN提取Proposal Regions,并利用原始CLIP对提取到的不同Region与准备好的描述进行匹配分类,并进一步组装成伪造的语义标签。
3.将准备好的Proposal Regions与语义标签在新的CLIP模型上进行Region-text对比学习,进而得到一个专精于Region信息的CLIP模型。
4.在预训练中,新的CLIP模型还会通过蒸馏策略学习原始CLIP的分类能力,以及进行全图级别的image-text对比学习,来维持新的CLIP模型对完整图像的表达能力。
第二阶段,将得到的预训练模型在检测模型上进行迁移学习。
RegionCLIP进一步拓展了已有跨模态大模型在常规检测模型上的表征能力,进而取得了更加出色的性能,如下图所示,RegionCLIP相比OVR-CNN在Novel类别上取得了较大提升。RegionCLIP通过一阶段的预训练有效地的提升了区域(Region)信息与多模态大模型之间的适应能力,但CORA认为其使用更大参数规模的跨模态大模型进行一阶段训练时,训练成本将会非常高昂。
论文地址:https://arxiv.org/abs/2303.13076
代码地址:https://github.com/tgxs002/CORA
CORA[6]已被收录于CVPR2023,为了克服其所提出当前OVD任务所面临的两个阻碍,设计了一个类DETR的OVD模型。如其文章标题所示,该模型中主要包含了Region Prompting与Anchor Pre-Matching两个策略。前者通过Prompt技术来优化基于CLIP的区域分类器所提取的区域特征,进而缓解整体与区域的分布差距,后者通过DETR检测方法中的锚点预匹配策略来提升OVD模型对新类别物体定位能力的泛化性。
CLIP 原始视觉编码器的整体图像特征与区域特征之间存在分布差距,进而导致检测器的分类精度较低(这一点与RegionCLIP的出发点类似)。因此,CORA提出Region Prompting来适应CLIP图像编码器,提高对区域信息的分类性能。具体地,首先通过CLIP编码器的前3层将整幅图像编码成一个特征映射,然后由RoI Align生成锚点框或预测框,并将其合并成区域特征。随后由 CLIP 图像编码器的第四层进行编码。为了缓解CLIP 图像编码器的全图特征图与区域特征之间存在分布差距,设置了可学习的Region Prompts并与第四层输出的特征进行组合,进而生成最终的区域特征用来与文本特征进行匹配,匹配损失使用了朴素的交叉熵损失,且训练过程中与CLIP相关的参数模型全都冻结。
CORA是一个类DETR的检测器模型,类似于DETR,其也使用了锚点预匹配策略来提前生成候选框用于框回归训练。具体来说,锚点预匹配是将每个标签框与最接近的一组锚点框进行匹配,以确定哪些锚点框应该被视为正样本,哪些应该被视为负样本。这个匹配过程通常是基于 IoU(交并比)进行的,如果锚点框与标签框的 IoU 超过一个预定义的阈值,则将其视为正样本,否则将其视为负样本。CORA表明该策略能够有效提高对新类别定位能力的泛化性。
但是使用锚点预匹配机制也会带来一些问题,比如只有在至少有一个锚点框与标签框形成匹配时,才可正常进行训练。否则,该标签框将被忽略,同时阻碍模型的收敛。进一步,即使标签框获得了较为准确的锚点框,由于Region Classifier的识别精度有限,进而导致该标签框仍可能被忽略,即标签框对应的类别信息没有与基于CLIP训练的Region Classifier形成对齐。因此,CORA用CLIP-Aligned技术利用CLIP的语义识别能力,与预训练ROI的定位能力,在较少人力情形下对训练数据集的图像进行重新标注,使用这种技术,可以让模型在训练中匹配更多的标签框。
相比于RegionCLIP,CORA在COCO数据集上进一步提升了2.4的AP50数值。
总结与展望
OVD技术不仅与当前流行的跨/多模态大模型的发展紧密联系,同时也承接了过去科研工作者对目标检测领域的技术耕耘,是传统AI技术与面向通用AI能力研究的一次成功衔接。OVD更是一项面向未来的全新目标检测技术,可以预料到的是,OVD可以检测并定位任意目标的能力,也将反过来推进多模态大模型的进一步发展,有希望成为多模态AGI发展中的重要基石。当下,多模态大模型的训练数据来源是网络上的海量粗糙信息对,即文本图像对或文本语音对。若利用OVD技术对原本粗糙的图像信息进行精准定位,并辅助预测图像的语义信息来筛选语料,将会进一步提升大模型预训练数据的质量,进而优化大模型的表征能力与理解能力。
一个很好的例子便是SAM(Segment Anything)[7],SAM不仅让科研工作者们看到了通用视觉大模型未来方向,也引发了很多思考。值得注意的是,OVD技术可以很好地接入SAM,来增强SAM的语义理解能力,自动地生成SAM需要的box信息,从而进一步解放人力。同样的对于AIGC(人工智能生成内容),OVD技术同样可以增强与用户之间的交互能力,如当用户需要指定一张图片的某一个目标进行变化,或对该目标生成一句描述的时候,可以利用OVD的语言理解能力与OVD对未知目标检测的能力实现对用户描述对象的精准定位,进而实现更高质量的内容生成。当下OVD领域的相关研究蓬勃发展,OVD技术对未来通用AI大模型能够带来的改变值得期待。
号外
为了推动OVD研究在国内的普及和发展,360人工智能研究院联合中国图象图形学学会举办了2023开放世界目标检测竞赛,目前竞赛正在火热报名中。竞赛可以帮助大家找到OVD方向的研究同好,与他们切磋交流,并能接触实际业务场景数据,体验OVD技术在实际生产中的优势与魅力,欢迎报名和转发。
参考文献
[1] Zareian A, Rosa K D, Hu D H, et al.
目录
一:什么是 Monorepo?
二:Monorepo 和其他结构的区别:
三:Monorepo的优缺点
3.1.优点
3.2.缺点
四:如何使用Monorepo
一:什么是 Monorepo? Monorepo 是一种将多个项目存放在同一个代码库中的开发策略。”mono” 表示单一 ,“repo” 是”repository”的缩写,意为多个项目共用一个代码库来管理依赖关系,同一套配置文件,统一构建部署流程等
二:Monorepo 和其他结构的区别: 首先,从上图中可以看到,对于Monorepo 和 Monolith repository ,他们之间有类似的地方,但不完全一样。Monolith repository 结构的项目,就如同一个整体,里面的每个部分脱离了这个项目都无法工作。而组成 Monorepo 的项目,或者说功能块,则是像积木一样,有自己的输入和输出,即使我们把它从这个项目中拆离出去,它也能自给自足,实现自己的功能。
其次,对于Monorepo,与之相对的是另一种流行的代码管理方式 MultiRepo,即每个项目对应一个单独的仓库来分散管理。作为传统的管理方式,Multirepo具备灵活度高、安全控制等特点,但同时也带了管理成本和写作成本的增加,依赖升级等问题。
从下图中可以明显的看出二者之间的区别:
三:Monorepo的优缺点 3.1.优点 1. 代码复用非常简单
在 Monorepo 中,由于所有的代码都在同一个项目下,如果引用其他一些已经定义过的功能模块,会非常方便。
我们只需要将复用频率高的代码,单独抽离出来成为一个 shared 之类的项目,那么其他所有的项目都只需要直接引用这个项目下的代码就可以了。而不用将这个项目重新打包,再在其他项目中使用。
2. 简化依赖管理
以往多个项目可能有一些相同的第三方依赖包,每个项目都需要下载一遍,而我们使用 Monorepo 的框架重构项目之后,这些依赖包就可以避免重复下载,同时也能通过配置在不同的项目之间复用。
3. 易于代码重构
当我们的一个库会影响到很多个项目时,修改了这个库之后,以往我们需要一个一个去更新对应受到影响的项目,进行相应的兼容适配工作,而修改一个问题又可能导致另外一个兼容问题。
而Monorepo 能够明确知道代码的影响范围,每次提交都会自动变更到受影响的项目中,也能通过编译时的错误检测机制,及时修正对应的代码,避免依赖兼容性问题的重复繁琐处理。
4. 便于跨组合作
由于 Monorepo 的项目是由一个一个独立的项目组成的,因此我们可以在每个子项目中使用自己的工作流和技术架构,即使将几个跨端跨语言的项目都放在一起也完全可以
所以在跨组合作的情况下,通过同一个Monorepo来开发,能省去大量中间沟通和协作的花费。
3.2.缺点 1. 缺乏每个项目的权限控制
Monorepo 由于将所有的子项目集成在同一个大的项目中,对于管理者来说,权限控制会变得很不方便,开发者每次拉取代码都会拉取所有的代码,无法进行精准的权限控制。
不过现在部分主流 Monorepo 框架都进行了这方面的功能开发。
2. 性能差
代码增多之后,整个git项目会变得越来越大,开发者拉取代码的时间也会变得更长。
3. 构建时间更长
Vue粒子特效使用教程(vue-particles插件)具体实现步骤 1.安装插件
npm install vue-particles -S
2.在main.js中注册
import Vue from ‘vue’
import VueParticles from ‘vue-particles’
Vue.use(VueParticles)
3.新建一个particle.vue文件 <template> <div class="login_container"> <vue-particles color="#fff" :particleOpacity="0.7" :particlesNumber="60" shapeType="circle" :particleSize="4" linesColor="#fff" :linesWidth="1" :lineLinked="true" :lineOpacity="0.4" :linesDistance="150" :moveSpeed="6" :hoverEffect="true" hoverMode="grab" :clickEffect="true" clickMode="push" class="lizi" style="height: 100%" > </vue-particles> </div> </template> <script></script> <style> .login_container { background-repeat: no-repeat; background-size: cover; height: 100%; position: absolute; width: 100%; opacity: 0.4; } </style> 4.属性介绍 color: String类型。默认’#dedede’。粒子颜色。
particleOpacity: Number类型。默认0.7。粒子透明度。
particlesNumber: Number类型。默认80。粒子数量。
shapeType: String类型。默认’circle’。可用的粒子外观类型有:“circle”,“edge”,“triangle”, “polygon”,“star”。
文章目录 1.引入库2. 马赛克2.1 使用马赛克 mosaic == True2.1.1 加载马赛克图像和标签 (load_mosaic) 2.2 不使用马赛克 mosaic == False 总结 1.引入库 代码如下(示例):
index = self.indices[index] # 获取数据集中的索引 hyp = self.hyp # 超参数 mosaic = self.mosaic and random.random() < hyp['mosaic'] # 是否使用马赛克增强 self.indices 是一个列表,包含数据集中的索引
hyp 是一个字典,包含了各种超参数,用于存储数据增强方法的概率和参数
例如,hyp[‘mosaic’] 表示使用马赛克增强的概率,hyp[‘mixup’] 表示使用 MixUp 增强的概率,hyp[‘hsv_h’]、hyp[‘hsv_s’] 和 hyp[‘hsv_v’] 分别表示 HSV 颜色空间增强的色调、饱和度和明度增益。
mosaic 通过检查 self.mosaic 和 random.random() < hyp[‘mosaic’] 来实现的。如果这两个条件都为真,则将 mosaic 变量设置为 True。
2. 马赛克 2.1 使用马赛克 mosaic == True 代码如下(示例):
vue首屏白屏原因大概有以下几点:
一.路由模式错误(路由重复或者没有配置路由) (1)由于把路由模式mode设置成history了,默认是hash
解决方法:将模式改为hash模式,或者直接把模式配置删除,而且history需要后端配合
(2)做动态路由时,next()放行与next(...to, replace)区别造成的白屏,实质是路由重复
(3)第一次正常访问,刷新后白屏,vuex没有与本地存储结合,刷新后导致数据丢失
二.dist中文件引用路径错误(vue项目打包的路径问题) 打包后的dist目录下的文件引用路径不对,因找不到文件而报错导致白屏
解决方法:vue.config.js中 publicPath: ''./"
三.浏览器不支持es6 在项目中使用了es6语法,一些浏览器不支持es6,造成编译错误不能解析而造成白屏
解决方法:
安装Babel ,Babel 会把这些新语法转译成较低版本的代码。
npm install --save-dev @babel/core @babel/cli @babel/preset-env 四.加载文件资源过大 单页面应用的 html 是靠 js 生成,因为首屏需要加载很大的js文件(app.js 和vendor.js),所以当网速差的时候会产生一定程度的白屏
解决方法:
路由懒加载,组件懒加载 路由懒加载 // 1、Vue异步组件技术: { path: '/home', name: 'Home', component: resolve => require(['../views/home.vue'], resolve) } // 2、es6提案的import() { path: '/', name: 'home', component: () => import('../views/home.vue') } // 3、webpack提供的require.ensure() { path: '/home', name: 'Home', component: r => require.
1.安装cron组件 1.1更新软件列表 apt-get update
1.2 安装 apt-get install cron
1.3 开启日志功能
1.3.1 安装rsylog组件 apt-get install rsyslog
1.3.2 配置日志记录 vim /etc/rsyslog.d/50-default.conf 配置文件的cron.* /var/log/cron.log前面的注释#去掉。
重启rsyslog服务
service rsyslog restart
待后续配置好cron启动程序后,会有日志输出到这个文件中 2.设定定时任务 定时任务有用户级别和系统级别两种方式的任务文件。
2.1用户级别crontab -e crontab -e是用户级别的计划任务文件。
2.1.1 crontab -e crontab -e
在末尾添加 * * * * * echo "Hello,world from crontab -e" >> /tmp/Helloworld.txt
每分钟输出Hello,world from crontab -e到/tmp/Helloworld.txt文件下。
2.1.2 service cron restart service cron restart重启cron服务。 2.1.2 文本编辑问题 如果出现下面的情况,则需要修改默认文本编辑器。
先关掉ssh连接,重连接ssh
sudo select-editor选择3,vim编辑器即可。
2.2 系统级别/etc/crontab /etc/crontab是系统级别的计划任务文件。在/etc/crontab文件中,需要指定任务的运行用户,/etc/crontab文件需要使用root用户来编辑。
连接VPN后无法上网 Windows Route 轻松解决 引言文档添加路由 引言 很多时候,我们公司的 VPN 为了不占用公司的外网带宽和安全起见,都会禁止访问外网。我们的电脑连接 VPN 后,所有的网络数据包都会走 VPN,从而导致我们无法访问互联网。而我们大多数情况下工作时需要连接互联网去查询资料。这时候我们可以使用 Windows Route 将我们的 VPN 网络和外网隔开,以实现同时可以访问内网和互联网。
Windows Route 还可以解决两个网关不在一个IP段内的网络互通。
文档 Windows Route
在 cmd 或者 powershell 中输入
route --help 添加路由 连接好 VPN,假如我们不加任何路由的话,所有的网络请求数据包都是走的 VPN,所以互联网是打不开的。在 cmd 中输入 route print 查看路由。 route print // 查看所有路由 route print -4 // 查看IPV4路由 下图中红框1代表的是本地路由,红框2代表的是 VPN 路由。我们可以看到我本地的网关是 192.168.50.1,VPN 网关是 192.168.253.1。而我们内网的服务器 IP 段为 192.168.1.2-192.168.1.255。那么我们只需要添加一条让 192.168.1.2-192.168.1.255 段的数据请求走 VPN 网关的路由就可以解决问题。
注:在路由表中,前一列为网络的目标地址,即可以访问的网络段,如:0.0.0.0 为所有网段
最好不要将自己本地的网关和服务器的网关设为一样,会出现冲突现象。这也是为啥我的网关是 192.168.50.1 而不是 192.168.1.1 的原因。因为公司服务器的网关是 192.168.1.1。
目录
一:pinia 是什么
二:pinia与vuex的区别
三:pinia的基本使用
3.1.安装
3.2.创建一个 pinia 实例
四:Pinia中的Store
4.1.什么是store
4.2.什么时候使用store
4.3.store的基本使用
4.4.state
4.5.getters
4.6.actions
一:pinia 是什么 Pinia本质上依然是一个状态管理的库,用于跨组件、页面进行状态共享(这点和Vuex、Redux一样)
Pinia最初是为了探索 Vuex 的下一次迭代会是什么样子,结合了 Vuex 5 核心团队讨论中的许多想法。最终,团队意识到Pinia已经实现了Vuex5中大部分内容,所以最终决定用Pinia来替代Vuex
二:pinia与vuex的区别 mutations不再存在,只保留state,getters和anctions三个概念,开发时候不用根据同步异步来决定使用 mutations 或 actions,pinia 中只有 actions
更友好的TypeScript支持
不再有modules的嵌套结构,可以灵活使用每一个store,它们是通过扁平化的方式来相互使用的
不再有命名空间的概念,不需要记住它们的复杂关系
三:pinia的基本使用 3.1.安装 用你喜欢的包管理器安装 pinia:
yarn add pinia # 或者使用 npm npm install pinia 注意:如果你的应用使用的 Vue 版本低于 2.7,你还需要安装组合式 API 包:@vue/composition-api
3.2.创建一个 pinia 实例 1)新建store文件夹,在此文件夹下新建一个index.js
import { createPinia } from 'pinia' //创建一个pinia实例 const pinia = createPinia() export default pinia 2)在main.
传统的UNIX操作系统与那些传统的MS-DOS操作系统不同,区别在于它们不仅是多重任务处理(multitasking)系统,而且还是多用户(multiuser)系统。
确切地说,这意味着什么呢?这意味着同一时间内可以有多个用户使用同一台计算机。虽然一台标准的计算机可能只包含一个键盘和一台显示器,但是它仍然可以同时被一个以上的用户使用。
例如,如果计算机连接到一个网络或者互联网中,远程用户可以通过ssh(安全shell)登录并且操作这台计算机。事实上,远程用户可以执行图形化应用程序,而且图形化的输出结果将会出现在远程显示器上。X窗口系统把这个作为基本设计理念的一部分,并支持这种功能。
为了保证多用户功能实际可用,系统特别设计了一种方案来保护当前用户不受其他用户操作的影响,毕竟,一个用户的操作不能导致计算机崩溃,一个用户的操作界面也不能显示属于另一个用户的文件。
1.所有者、组成员和其他所有用户 当我们试图查看类似/etc/shadow的文件时,会遇到下面的问题
产生这种错误信息的原因是,作为一个普通用户,没有读取这个文件的权限。
在UNIX安全模式中,一个用户可以拥有(own)文件和目录。当一个用户拥有一个文件或者目录时,它将对该文件或目录的访问权限拥有控制权。反过来,用户又归属于一个群组(group),该群组由一个或多个用户组成,组中用户对文件和目录的访问权限由其所有者授予。除了可以授予群组访问权限之外,文件所有者也可以授予所有用户一些访问权限,在UNIX术语中,所有用户是指整个世界(world)。使用id命令可以获得用户身份标识的相关信息,如下所示
查看id命令的输出结果。在创建用户账户的时候,用户将被分配一个称为用户ID(user ID)或者uid的号码。为了符合人们的使用习惯,用户ID与用户名一一映射。同时用户将被分配一个有效组ID(primary group ID)或者称为gid,而且该用户也可以归属于其他的群组。
那么这些信息是从哪里来的呢?类似于Linux系统中的很多情况,这些信息来源于一系列的文本文件。用户账户定义在/etc/passwd文件中,用户组定义在/etc/group文件中,文件/etc/shadow中保存了用户的密码信息。
对于每一个用户账户,/etc/passwd中都定义了对应用户的用户(登录)名、uid、gid、账户的真实姓名、主目录以及登录shell信息。如果查看文件/etc/passwd和/ect/group的内容,那么你将会发现除了普通用户账户信息之外,文件中还有对应于超级用户(uid为0)和其他不同种类的系统用户的账户信息。
许多类UNIX系统会把普通用户分配到一个公共的群组中(比如users),然而现在的Linux操作则是创建一个独一无二的,只有一个用户的群组,而且组名和用户的名字相同,这使得特定类型的权限分配变得更加容易。
2.读取、写入和执行 对文件和目录的访问权限是按照读访问、写访问以及执行访问来定义的。当我们查看ls命令的输出结果时,可以得到一些线索,了解其实现方式。
列在输出结果中的前10个字符表示的是文件属性(file attribute,见下表),其中第一个字符表示文件类型
- rw- r-- r-- 1 2 3 4 1:文件类型 2:所有者权限 3:组权限 4:其他用户权限 属性文件类型.普通文件d目录文件l符号链接。注意对于符号链接文件,剩下的文件属性始终是rwxrwxrwx,它是个伪属性值,符号链接指向的文件的属性才是真正的文件属性c字符设备文件。该文件类型表示以字节流形式处理数据的设备,如终端或调制解调器b块设备文件。该文件类型表示以数据块方式处理数据的设备,如硬盘驱动或者光盘驱动 文件属性找中剩下的9个字符称为文件模式,分别表示文件所有者、文件所属群组以及其他所有用户对该文件的读取、写入和执行权限。
分别设置r(读取)、w(写入)和x(执行)的模式属性将会对文件和目录带来不同的影响
属性文件目录r允许打开和读取文件如果设置了执行权限,那么允许列出目录下的内容w允许写入或者截短文件;如果也设置了执行权限,那么目录中的文件允许被创建、被删除以及被重命名但是该权限不允许重命名或者删除文件 是否能重命名和删除文件由目录权限决定x允许把文件当做程序一样执行。用脚本语言写的程序必须被设置为可读,以便能被执行允许进入目录下,例如cd directory 下表给出了一些文件属性设置的例子。
文件属性含义-rwx------普通文件,文件所有者具有读取、写入和执行权限。组成员和其他所有用户都没有任何访问权限-rw-------普通文件,文件所有者具有读取和写入权限,组成员和其他所有用户都没有任何访问权限-rw-r–r–普通文件,文件所有者具有读取和写入权限,文件所有者所在群组的成员可以读取该文件。该文件对于所有用户来说都是可读的-rwxr-xr-x普通文件,文件所有者具有读取、写入和执行权限,其他所有用户也可以读取和执行该文件-rw-rw----普通文件,只有文件所有者和文件所有者所在群组的成员具有读取和写入的权限lrwxrwxrwx符号链接。所有的符号链接文件显示的都是“伪”权限属性,真正的权限属性由符号链接指向的实际文件决定d-wxrwx—目录文件,文件所有者和所有者所在群组的成员都可以进入该目录,而且可以创建、重命名和删除该目录下的文件drwxr-x—目录文件,文件所有者可以进入目录,而且可以创建、重命名和删除该目录下的文件。所有者所在群组的成员可以进入该目录,但是不能创建、重命名和删除该目录下的文件 2.1 chmod更改文件模式 我们可以使用chmod命令来更改文件或者目录的目录的模式(权限)。需要注意的是只有文件所有者和超级用户才可以更改文件或者目录的模式。chmod命令支持两种不同的改变文件模式的方式,八进制数字表示法和符号表示法。
2.1.1 八进制数字表示法 八进制数字表示法指的是使用八进制数字来设置所期望的权限模式。因为每个八进制数字对应着3个二进制数字,所以这种对应关系正好可以和用来存储文件模式的结构方式一一映射
八进制二进制文件模式0000—1001–x2010-w-3011-wx4100r–5101r-x6110rw-7111rwx 通过使用3位八进制数字,我们可以分别设置文件所有者、组成员和其他所有用户的文件模式。
通过传递参数600,我们可以设置文件所有者的读写权限,而取消组用户和其他所有用户的权限。
常用的几个映射关系:7(rwx)、6(rw-)、5(r-x)、4(r–)和0(—)
2.1.2 符号表示法 chmod命令支持一种符号表示法来指定文件模式。该符号表示法分为三部分:更改会影响谁、要执行哪个操作以及要设置哪种权限。可以通过字符u、g、o和a的组合来指定要影响的对象
符号含义uuser的简写,表示文件或者目录的所有者ggroup的简写,表示文件所属群组oothers的简写,表示其他所有用户aall的简写,是u、g、o的组合 如果没有指定字符,则假定使用all。操作符“+”表示添加一种权限,“-”表示删除一种权限,“=”表示只有指定的权限可用,其他所有的权限都被删除。
权限由字符“r”、“w”和“x”来指定。如下图
符号含义u+x为文件所有者添加可执行权限u-x删除文件所有者的可执行权限+x为文件所有者、所属群组和其他所有用户添加可执行权限,等价于a+xo-rw除了文件所有者和所属群组之外,删除其他所有用户的读写权限go=rw除了文件所有者之外,设置所属群组和其他所有用户具有读写权限。如果所属群组和其他所有用户之前已经具有可执行权限,那么删除他们的可执行权限u+x,go=rx为文件所有者添加可执行权限,同时设置所属群组和其他所有用户具有读权限和可执行权限。指定多种权限时,需用逗号分隔 2.2 umask设置默认权限 umask命令控制着创建文件时指定给文件的默认权限。它使用八进制表示法来表示从文件模式属性中删除一个位掩码。
首先,删除foo.txt文件存在的所有副本,以保证一切都是重新开始。下一步运行不带任何参数的umask命令,查看当前掩码值,得到的值是0022(0002是另一个常用的默认值),它是掩码的八进制表示形式。接着创建文件foo.txt的一个新实例,查看该文件的权限,可以发现,文件所有者获得读写权限,而组和其他所有用户则只获得读权限。组和其他所有用户没有写权限的原因在于掩码值。
在设置掩码为0000(实际上是关闭该功能)时,可以看到组和其他所有用户也拥有写权限了。为了理解它是如何实现的,再看看八进制数。
如果把该掩码展开成二进制形式,然后再与属性进行对比
名称形式原始文件模式— rw- rw- rw-掩码000 000 010 010结果— rw- r-- r– 先忽略掉掩码中前面的0,观察掩码中出现1的地方,将会发现1的位置对应的属性被删除,这就是掩码的操作方式。掩码的二进制数值中每个出现1的位置,其对应的属性都被取消。
调用api的基本步骤如下:
1.导入requests库,这是一个常用的发送和处理http请求的库。
2.创建一个请求对象,指定请求的url,方法,参数,头部等信息。
3.发送请求,获取响应对象。
4.检查响应的状态码,内容,格式等信息。
5.如果响应是json格式,可以使用json模块解析成python字典或列表。
下面是一个示例代码,调用一个获取国际空间站位置的api:
# 导入requests库 import requests # 导入json库 import json # 创建请求对象 url = "http://api.open-notify.org/iss-now.json" method = "GET" params = {} headers = {} # 发送请求,获取响应对象 response = requests.request(method, url, params=params, headers=headers) # 检查响应状态码 if response.status_code == 200: print("请求成功") else: print("请求失败") # 检查响应内容 print(response.text) # 检查响应格式 print(response.headers["Content-Type"]) # 如果响应是json格式,解析成python字典 if response.headers["Content-Type"] == "application/json": data = json.loads(response.text) print(data)
helm中文官网地址:
https://helm.sh/zh/docs/intro/install/ 1、安装方式根据系统不同有脚本安装、二进制安装等不同的安装方式,我选择使用二进制安装
2、点击需要的版本后选择适合自己的版本
3、直接点击下载,也可以右键复制链接地址,直接使用wget在服务器中下载
wget https://github.com/helm/helm/archive/refs/tags/v3.11.3.tar.gz 4、解压并根据自己选择安装helm2还是helm3
[root@k8s-master01 ~]# tar xf v3.11.3.tar.gz ^C [root@k8s-master01 ~]# cd helm-3.11.3/scripts/ [root@k8s-master01 scripts]# ls coverage.sh get get-helm-3 release-notes.sh sync-repo.sh util.sh validate-license.sh [root@k8s-master01 scripts]# ./get-helm-3 Downloading https://get.helm.sh/helm-v3.11.3-linux-amd64.tar.gz Verifying checksum... Done. Preparing to install helm into /usr/local/bin helm installed into /usr/local/bin/helm 您在 /var/spool/mail/root 中有新邮件 [root@k8s-master01 scripts]# helm version version.BuildInfo{Version:"v3.11.3", GitCommit:"323249351482b3bbfc9f5004f65d400aa70f9ae7", GitTreeState:"clean", GoVersion:"go1.20.3"} 备注:get是helm2的版本 get-helm-3是3的版本
内核的shmall和shmmax参数 SHMMAX=配置了最大的内存segment的大小:这个设置的比SGA_MAX_SIZE大比较好。
SHMMIN=最小的内存segment的大小
SHMMNI=整个系统的内存segment的总个数
SHMSEG=每个进程可以使用的内存segment的最大个数
配置信号灯( semphore )的参数: SEMMSL=每个semphore set里面的semphore数量:这个设置大于你的process的个数吧,否则你不得不分多个semphore set,好像有process+n之说,我忘了n是几了。
SEMMNI=整个系统的semphore set总数
SEMMNS=整个系统的semphore总数
shmall是全部允许使用的共享内存大小,shmmax是单个段允许使用的大小。这两个可以设置为内存的90%。例如16G内存,16*1024*1024*1024*90%=15461882265,shmall的大小为 15461882265/4k(getconf PAGESIZE可得到)=3774873。
修改/etc/sysctl.conf
kernel.shmmax=15461882265
kernel.shmall=3774873
kernel.msgmax=65535
kernel.msgmnb=65535
执行sudo sysctl -p
可以使用ipcs -l看结果。ipcs -u可以看到实际使用的情况
Linux内存管理 本文档针对OOP8生产环境,具体优化策略需要根据实际情况进行调整;本文档将在以下几个方面来阐述如何针对RedHat Enterprise Linux进行性能优化。
1) Linux Proc文件系统,通过对Proc文件系统进行调整,达到性能优化的目的。
2) Linux性能诊断工具,介绍如何使用Linux自带的诊断工具进行性能诊断。
加粗斜体表示可以直接运行的命令。
下划线表示文件的内容。
二、/proc/sys/kernel/优化 1)/proc/sys/kernel/ctrl-alt-del 该文件有一个二进制值,该值控制系统在接收到ctrl+alt+delete按键组合时如何反应。这两个值分别是:
零(0)值,表示捕获ctrl+alt+delete,并将其送至 init 程序;这将允许系统可以安全地关闭和重启,就好象输入shutdown命令一样。
壹(1)值,表示不捕获ctrl+alt+delete,将执行非正常的关闭,就好象直接关闭电源一样。
缺省设置:0
建议设置:1,防止意外按下ctrl+alt+delete导致系统非正常重启。
2)proc/sys/kernel/msgmax
该文件指定了从一个进程发送到另一个进程的消息的最大长度(bytes)。进程间的消息传递是在内核的内存中进行的,不会交换到磁盘上,所以如果增加该值,则将增加操作系统所使用的内存数量。
缺省设置:8192
3)/proc/sys/kernel/msgmnb
该文件指定一个消息队列的最大长度(bytes)。
缺省设置:16384
4)/proc/sys/kernel/msgmni
该文件指定消息队列标识的最大数目,即系统范围内最大多少个消息队列。
缺省设置:16
5)/proc/sys/kernel/panic
该文件表示如果发生“内核严重错误(kernel panic)”,则内核在重新引导之前等待的时间(以秒为单位)。
零(0)秒,表示在发生内核严重错误时将禁止自动重新引导。
缺省设置:0
6)proc/sys/kernel/shmall
该文件表示在任何给定时刻,系统上可以使用的共享内存的总量(bytes)。
缺省设置:2097152
7)/proc/sys/kernel/shmmax
该文件表示内核所允许的最大共享内存段的大小(bytes)。
缺省设置:33554432
建议设置:物理内存 * 50%
isOpenMode() { //平台、设备和操作系统 var system = { win: false, mac: false, xll: false, ipad: false }; //检测平台 var p = navigator.platform; system.win = p.indexOf("Win") == 0; system.mac = p.indexOf("Mac") == 0; system.x11 = (p == "X11") || (p.indexOf("Linux") == 0); system.ipad = (navigator.userAgent.match(/iPad/i) != null) ? true : false; //跳转语句,如果是手机访问就自动跳转到wap.baidu.com页面 if (system.win || system.mac || system.xll || system.ipad) { var ua = navigator.userAgent.toLowerCase(); if (ua.match(/MicroMessenger/i) == "micromessenger") { alert("在PC端微信上打开的"); return 2; } else { alert("
使用时间范围选择控件:设置初始值,获取值和清空
<a-form-item label="时间" format="YYYY-MM-DD" > <a-range-picker v-model="date"/> </a-form-item> data(){ return { date:[] } } created(){ let now=new Date() let start=new Date(now.setFullYear(now.getFullYear()-1)) let end=new Date() this.date=[moment(start, 'YYYY-MM-DD'), moment(end, 'YYYY-MM-DD')] // 设置初始值 } ... // 清空 this.date=[] // 获取值 params.startDate = moment(this.date[0]).format("YYYY-MM-DD") params.endDate=moment(this.date[1]).format("YYYY-MM-DD")
对于普通问题可以用\ \或者" "扩起来就可以解决,但是对于脚本中的括号使用这种方法并不能使用,原因是不能改变文件名称。
原来在脚本中需要使用有括号的代码,运行就会出现这种错误,但是sampleDict生成的名称改变更复杂,所以直接用*来代替文件名解决问题。
为方便大家阅读,源码先行奉上
github源码链接 https://github.com/Recycle1/Live-video-demo
csdn源码链接 https://download.csdn.net/download/weixin_52263647/85070250
需要注意的一点是!!!:上述的代码需要更改IP地址为你自己的IP地址,博主在做完这个demo后禁用了1935端口号,因此无法直接使用博主的云服务器,同时如果是阿里云服务器,一定要记得在安全组中放行相应的端口号,否则无法正常推流。
最近要做一个有把视频从手机端推流,在另一端拉流功能的app,所以就学习了一下直播功能,这两个功能比较类似,找到了一些收藏点赞比较多的文章,按着他们的记录一步一步的做了下来,但是文章大多都是几年前写的,可能也是我懂的比较少,捣鼓了好几天,按着他们做的照着做,还是出现了各种各样的问题,所以我汇总了一些博文的内容,终于是实现了。
首先准备工作,不光需要有Android stdio,还需要有自己的服务器,这里我租用了阿里云的云服务器(linux系统),之后的文章中,从Android端的编写到服务器端的配置都会有所介绍。最后测试实现的结果,可以先在电脑上下载一个VLC
具体的一些流程是:
在android端调用yaesa库进行摄像头采集、编码,随后向srs服务器rtmp推流在服务器端部署srs流媒体服务器在android端调用vitamio实现取流播放 一 Android端搭建 android实现的功能一个是采集摄像头的内容,然后将视频内容推流到服务器端,另一个是从服务器端拉流到手机播放视频。
以下是我认为比较好的博文
Android直播实现(一)Android端推流、播放
首先需要调用yaesa,链接如下
https://github.com/begeekmyfriend/yasea
将yaesa项目clone下来,对我们有用的就是其中library这部分,我们将这个文件夹作为library导入到自己的android项目中,导入的过程就是在顶部的功能那里,依次点击
File -->new–>import Module
出现上面的画面,我们从里面找到刚才下载的yeasa中的library文件夹,放入里面,导入成功
然后需要在我们自己的项目,也就是app这个目录下导入library这个依赖,具体的方法可以等之后在那些引用外部依赖的代码标红时(出错),看android stdio给的推荐解决方案,点击(import dependence)即导入依赖,也可以直接通过File–>Project Structure->Dependencies,点击加号添加依赖
然后对于拉流操作,我们需要使用vitamio是实现功能,所以我们同样需要引入vitomio,这里就到了一个大坑!!!
我按着第一篇博文的方法,从他给出的demo
https://github.com/SiKang123/LiveTest
或者从各种博文都推荐的vitomio地址https://github.com/yixia/VitamioBundle 将vitomio导入到android端(和上面的操作一样)
但是,本以为大功告成了,结果vitomio在测试时一直出现问题,找不到vinit.so文件,我查了各种文章,都找不到解决的办法,最后我看到一个博主出现的虽然不是这个问题,但是vitomio也是运行不了,于是他换了一个vitomio的下载地址,没有用上面的链接,成功解决了自己的问题,我试了一下,也是把我的问题解决了
引用vitamio框架提示libffmpeg.so、libstlport_shared.so无法找到的错误
他引用的vitomio项目地址是这个
https://github.com/yixia/VitamioBundleStudio
上面这个是可以用的,但是也需要做一些修改,首先把vitomio文件夹根据我们上面讲到的方法放入自己的项目中,随后更改vitomio文件下的build.gradle文件
改为这样
随后更改vitomio文件夹下的MediaPlayer.java文件
其实这个我也不知道问题出在哪里,后面运行的时候发现这里报错,LIB_ROOT这个变量的值有问题,所以这里我索性去掉了if语句,运行发现没有问题
这样,外部引用库就导入完成了,文件结构长这个样子
之后根据第一篇博文给的链接
https://github.com/SiKang123/LiveTest
把他的xml文件activity文件我们按着他写的写在我们自己的文件里
这样,android端就配置完成了,之后,我们开始配置服务器端
二 服务器端搭建 在服务器搭建这里,不是很了解的也没关系,现在搭建服务器有很多工具,操作起来不是很难,也不需要写很多命令,这里,我是用我租用的阿里云服务器(Linux系统)配置srs流媒体服务器
准备工作
需要有自己的服务器,工具类,我用的是宝塔面板,关于宝塔面板如何安装,使用,以及站点搭建,可以看我之前写的这篇文章
阿里云服务器宝塔面板的安装
一些比较方便的工具还有xshell,xftp这两个软件,一个是写命令的,一个是把自己电脑的文件传到服务器里的,xshell的功能宝塔面板里也有,但是xshell功能更加全面,xftp建议下载一个,因为这个传文件确实很方便
在宝塔面板这里,通过软件商店,我下载了nginx服务器,mysql,phpmyadmin等,这些是一些比较基础的配置(很方便,只要找到相应软件,点击安装,即可完成服务器基本配置工作)
具体内容
关于配置srs的大致思路,可以看这篇文章
linux部署安装SRS流媒体服务器教程
上面这篇博文通过crt进行安装,我们用
宝塔面板+xftp(+xshell)
就很方便,首先下载srs
https://github.com/ossrs/srs
最好是下载releases版本的,在上面的网页往下划,找到这里,选一个你相中的,
点进去以后,下载这个比较好
在自己电脑里解压就可以然后通过xftp传到服务器的root文件夹里面
1.在宝塔终端或在xshell输入命令行
2.进入trunk文件夹下,之后的操作都在此文件夹下进行
输入以下内容编译文件
./configure && make 3.
前言 链表是一种基础的线形数据结构,但是其与顺序表有着较大的差别。但是由于链表与顺序表均为线形结构,本篇将穿插对比分析它们在部分性能上的优劣性。建议萌新先学习顺序表,再来看链表。
【结构体解析】传送门:http://t.csdn.cn/iawZx。
【顺序表解析】传送门:http://t.csdn.cn/TZ5mw。
1 链表的基本思路 1.1 思路引入 相信大家一定都会串珠子,当我们有一根线和若干珠子的时候,我们可以把珠子一个一个地串到线上,这样就形成了一条链子。当被串成链子后,珠子就不会分散很,更加方便我们管理。这是一个简单的生活技巧。
1.2 基本思路 链表的思路其实就是参考了串珠子。如果我们把每一个数据存储在一个珠子里,再用某种方式将这些珠子串起来,不就形成一条链子了吗?这就是数据结构中的链表的基本思路。
在链表中,我们通常把这些存储数据的珠子称为节点。那么我们要怎么样将这些珠子串在一起呢?C语言的结构体提供了一种用法,叫做结构体的自引用。我们可以在结构体中声明一个与该结构体同类的指针,这样一来我们就可以通过在一个节点中保存下一个节点的地址的方式来将这些节点串在一起。 下面为代码和图片演示,这是一个节点的声明,这类节点中包含一个整型变量data和一个指针next,那么在该类节点中,每个节点可以存放一个整型数据和一个节点地址,通过地址又可以找到下一个节点。这样一来,只要我们能找到第一个节点,就能访问链表中任何一个节点。由于数据量是有限的,因此链表也不可能无限长,我们一般将链表中最后一个节点置空(防止越界访问)。
struct SListNode { int data; struct SListNode* next; }; 1.3 注意事项 在我们的想象中,链表是一种线形结构,每个节点都被我们通过指针串在一起。但实际上,在内存当中,链表的各个节点的地址并不一定是连续的,而大概率是分散的。这里需要理解,我们是通过在节点中保存下一个节点的地址,再通过地址来找到下一个节点,而不是将所有节点移动到一块连续的空间。
这是与顺序表不同的地方。顺序表的数据是存储在一块连续的内存空间上的。
2 单链表 单链表,即单向链表。单向链表顾名思义,就是只有一个方向,也就是说只能通过前一个节点找到后一个节点,而不能从后一个节点找到前一个节点。
由于静态版数据结构在大部分场景下应用价值不大,本篇主要介绍动态版链表。
大部分链表OJ题都采用这种链表结构,如图(图中一个圆圈表示一个节点,圈内数字表示该节点所储存的数据,箭头表示节点中指向下一个节点的指针)。
2.1 接口 作为一种基础的数据结构,链表的基本功能当然也就是增删查改了。
而链表的基本思路是通过连接节点的方式将数据联系起来,那么我们的增加和删除数据其实要做的就是在合适的位置增加和删除节点。
#pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> typedef int SLTDataType; typedef struct SListNode { SLTDataType data; struct SListNode* next; }SListNode; // 动态申请一个节点 SListNode* BuySListNode(SLTDataType x); // 单链表打印 void SListPrint(SListNode* plist); // 单链表尾插 void SListPushBack(SListNode** pplist, SLTDataType x); // 单链表的头插 void SListPushFront(SListNode** pplist, SLTDataType x); // 单链表的尾删 void SListPopBack(SListNode** pplist); // 单链表头删 void SListPopFront(SListNode** pplist); // 单链表查找 SListNode* SListFind(SListNode* plist, SLTDataType x); // 单链表在pos位置之后插入x void SListInsertAfter(SListNode* pos, SLTDataType x); // 单链表删除pos位置之后的值 void SListEraseAfter(SListNode* pos); // 单链表的销毁 void SListDestroy(SListNode* plist); 2.
海哥牛逼
这里写自定义目录标题 一、C语言如何变成汇编1、裸函数 二、调用约定1、常见的几种调用约定 三、程序的真正入口四、数据类型4.1 C语言中的数据类型 作业 一、C语言如何变成汇编 1、裸函数 裸函数使用特殊方式定义,编译器和连接器并不会为其生成提升堆栈,开辟填充缓冲区和堆栈平衡等代码。
普通函数void Function() {}可以直接调用,并运行通过;而裸函数void __declspec(naked) Function() {}直接调用运行时不通过。
这是因为前者编译器为其生成了返回的汇编代码,在函数运行结束时有ret汇编代码返回call调用前的下一跳地址;而后者没有编译器生成的返回代码,执行call时将下一跳地址入栈,但结束时没有ret指令返回,使得cpu执行到了int3或其他区域,进而报错。 无参无返回裸函数 void __declspec(naked) Function() { __asm{ ret } } 或者 void __declspec(naked) Function() { __asm{ //保留调用前的栈底 push ebp //提升堆栈 mov bep,esp sub esp,0x40 //保存现场 push ebx push esi push edi //填充缓冲区 lea edi,dword ptr ds:[ebp-0x40] mov eax,0xCCCCCCCC mov ecx,0x10 rep stosd //恢复现场 pop edi pop esi pop ebx //降低堆栈 mov esp,ebp //恢复栈底 pop ebp ret } } 有参有返回裸函数(参数在函数调用前使用push入栈,局部变量在缓冲区,返回值一般在eax) int __declspec(naked) Plus(int x, int y){ __asm{ //保留调用前的栈底 push ebp //提升堆栈 mov ebp,esp sub esp,0x40 //保存现场 push ebx push esi push edi //填充缓冲区 lea edi,dword ptr ds:[ebp-0x40] mov eax,0xCCCCCCCC mov ecx,0x10 rep stosd //函数的核心功能:参数执行计算过程 mov eax,dword ptr ds:[ebp+0x8] add eax,dword ptr ds:[ebp+0xC] //恢复现场 pop edi pop esi pop ebx //降低堆栈 mov esp,ebp //恢复栈底 pop ebp ret } } 二、调用约定 1、常见的几种调用约定 三、程序的真正入口 3.
在哪个位置拍摄快照就会从哪个位置发一个分支出去,例如下图中的B->D
在VMware Workstation Pro的这个地方可以拍摄快照。
桥接模式 将虚拟机的Linux的IP地址设置成和外界一样的网段,那么张三的虚拟系统Linux就可以和李四,王五通讯。
NAT模式 使用NAT模式会在主机上会产生一个虚拟IP,然后这个ip和虚拟的Linux系统之间会产生一个网络,它们之间就就可以通讯;而且这个虚拟的Linux系统可以通过192.168.0.50这个代理去和外界通讯
主机模式 主机模式是一个独立的系统,不和外界发生联系。