1. 安装postcss-pxtorem npm install postcss-pxtorem --save-dev 2. 安装lib-flexible npm i -s amfe-flexible 3. 在main.js引入插件 import 'amfe-flexible' 4. 配置postcss.config.js文件 在根目录,和package.json同级,创建一个名为postcss.config.js的文件。
module.exports = { "plugins": { "postcss-pxtorem": { rootValue: 37.5, // Vant 官方根字体大小是 37.5(根据使用的ui组件?定义根元素大小? propList: ['*'], selectorBlackList: ['.norem'] // 过滤掉.norem-开头的class,不进行rem转换 } } } 在index.html头部加入手机端自适应meta
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
MD5概念: MD5全称为信息-摘要算法(哈希算法),是计算机安全领域的散列函数,用于确保消息的完整性。另外摘要算法还有SHA1,具体请度娘。MD5是一种单向加密,它的加密不可逆,它将任意长度的字符串,经过算法计算后生成固定长度的数据,一般为16位表示 。这种加密方式最简单同时也最直接。
vue项目使用: 安装: npm install --save js-md5 引用: 1. 局部使用: import md5 from 'js-md5' md5('MD5加密') 2. 全局使用: import md5 from 'js-md5'; Vue.prototype.$md5 = md5; this.$md5('MD5加密') 案例: 一般在向后端传递密码的时候需要用MD5加密一下,后端的话也是用MD5解密,我这里直接是在全局定义了MD5,因为本次这个项目有很多接口需要传递密码,所以定义全局比较方便,上面我已经把局部和全局的两种方式都已经列出来了。
registerClick() { this.$refs.ruleFormRef.validate(async (valid) => { try { if (!valid) return false; let parameter = { microservices: "lmall/login/supplier/merchant/signUp", mobile: this.ruleForm.phone, captcha: this.ruleForm.code, // MD5加密 password: this.$md5(this.ruleForm.checkPass), nickname: this.ruleForm.name, }; let request = await this.$PostData(parameter); if (request.ret === 200) { this.$message.success("注册成功"); this.
一、查看原有的代码
首先我们看一下Shiro原有的账号密码登录关键代码,分析一下该如何改造,
Subject currentUser = ShiroKit.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password.toCharArray()); 从这两行代码看出,我们需要重写一个获得Token的方法。
二、改造
1.新建一个枚举类,这个也可以不建立,因为我这边的系统免密登录和账号密码登录的情况有存在,所以我加了一个枚举类进行判断,用户具体执行哪一个登录方法。
枚举类具体代码如下:
package com.stylefeng.guns.core.shiro.secretfree; /** * 登录类型枚举类 */ public enum LoginType { PASSWORD("password"), // 密码登录 NOPASSWD("nopassword"); // 免密登录 private String code;// 状态值 private LoginType(String code) { this.code = code; } public String getCode() { return code; } } 2.新建自定义的UserRealem类继承AuthorizingRealm
package com.stylefeng.guns.core.shiro; import com.stylefeng.guns.core.shiro.ShiroUser; import com.stylefeng.guns.core.shiro.factory.IShiro; import com.stylefeng.guns.core.shiro.factory.ShiroFactroy; import com.stylefeng.guns.core.shiro.secretfree.CustomeToken; import com.stylefeng.guns.core.util.ToolUtil; import com.stylefeng.guns.modular.system.model.User; import com.stylefeng.guns.modular.system.service.IUserService; import org.
目录
一、linux内安装gdb
二、使用gdb调试程序步骤
1.执行程序
2.调试
设置断点
开始调试
debug版本与release版本的说明: debug版本:在编译阶段会加入某些调试信息,是给程序员使用的
release版本:linux默认的版本,给用户的发行版本,没有调试信息,调试信息是在编译过程中加入到中间文件.o文件的。
使用gdb调试程序的前提是:待调试的程序中包含有调试符号信息,即生成debug版本的程序。
一、linux内安装gdb 参照vim安装方法 当再次输入为如下界面,即安装成功 二、使用gdb调试程序步骤 1.执行程序 gdb命令run(可以简写为r)执行装载代码,在run命令之后可以指定程序运行所需要的参数。(gdb) r 2.调试 设置断点 如果程序中存在断点,则会在断点处自动暂停。通过使用gdb逐步调试代码,可以看到程序内部是如何运行的,还可以知道什么命令正在执行,变量的值的变化以及其他一些细节问题。 与断点相关命令:
首先,调用gdb,装载子程序:以main.c示例 $gdb main 如要在GDB启动后载入,使用file命令:(gdb) file main1 开始调试 gcc -o test test.c -g //编译生成test执行文件
调试信息是在编译阶段进行的,而不是链接阶段
gdb test //在gdb内调试test文件
b +行号: 加断点 通过使用break命令(可简写为b)指定一个特定的位置设置断点。指定一个特定的位置设置断点,当程序运行到这个位置时就被中断,然后把程序的控制权交给调试器和程序员。设置断点的最简单形式——在break命令后加入行号来在该行加入断点,如下所示:
设置断点时也可以进行条件判断,即只有条件为真,程序到达指定行或函数时才停下来。 (gdb) b 9 if i>9 info b / info break 查看断点信息,包括编号、类型、地址等。
delete +断点编号 : 删除断点 图示为删除断点编号为2的断点信息
在delete命令后加入断点编号可以删除指定的断点。不指定断点号则删除所有的断点。 (gdb) d 1 --删除编号为1的断点delete命令后面可以跟一个范围 (gdb) d 1-6 --删除编号为1~6的断点也可以使用clear来删除指定代码行上的断点。clear命令后面可以跟一个范围。 (gdb) clear 9 --删除第9行上的所有断点可以使用disable命令使某个断点暂时失效。disable命令可加断点号来禁用指定断点,否则会将所有断点禁用。断点在禁用之后可以用enable命令来恢复使用。 c 在断点后继续运行程序,可使用continue命令(简写为c)
关闭屏幕,求最小关闭次数,应该用BFS更好,但此处DFS更容易理解
#include <bits/stdc++.h> using namespace std; vector<int> path; vector<vector<int> > cur; vector<int> pat; int n; int flag = 0; bool isVaild(){ for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ if(cur[i][j] == 1) return false; } } return true; } void flip(int cnt){ int i = cnt / n; int j = cnt % n; cur[i][j] = !cur[i][j]; int next[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; for(int k = 0; k < 4; k++){ int ni = i + next[k][0]; int nj = j + next[k][1]; if(ni >= 0 && ni < n && nj >= 0 && nj < n){ cur[ni][nj] = !
一、什么是Drawcalls 在Unity中,每次CPU准备数据并通知GPU的过程就称之为一个DrawCall。这个过程会指定一个Mesh被渲染,绘制材质。
二、Drawcalls有什么影响 为了CPU和GPU可以进行并行工作,需要一个命令缓冲区,由CPU向其中添加命令,然后由GPU从中读取命令,这样就实现了通过CPU准备数据,通知GPU进行渲染。在每次调用DrawCall之前,CPU需要向GPU发送很多内容,主要是包括数据,渲染状态,命令等。所以如果DrawCall数量过多就会导致CPU进行大量计算,进而导致CPU的过载,影响程序运行效率。
三、查看Drawcalls 在unity中查看drawcalls有2个方法,如图1所示查看Game窗口中的State下的Batces,这个数量和drawcalls数量相同。第二种方法是查看Window → Analysis → Profiler 中的Rendering下的Drawcalls,如图2所示。 图1 图2
四、Drawcalls优化 1. 3D场景优化 1.1 静态批处理 静态批处理首先需要到 Project Setting → Player → Other Setting 中将Static Bathing 勾选上,然后把需要静止的物体标记为Static,然后无论大小,相同材质的都会组成Batch。如下图所示,当没有勾选 static 的时候,场景中2个cube的drawcalls为4,勾选了之后drawcalls变成了3。
1.2 动态批处理 动态批处理需要在Project Setting → Player → Other Setting 中将Dynamic Bathing 勾选上,Unity会自动将使用相同材质的物体合并处理。如图所示,场景中虽然有3个cube,但是drawcalls还是只有3。
不过,在使用动态批处理的时候,具有一些局限性。
顶点属性最大限制900的可移动物体,
使用lightmap的物体不行进行批处理
使用多通道的shader也不会进行批处理
缩放比不同的物体不会批处理
1.3 勾选 Enable GPU Instancing 在使用大量重复的物体时,需要将该物体的材质的 Enable GPU Instancing 勾选上,这样Unity会将Mesh相同的物体合并处理,常用于树木,植被,粒子等。如图所以虽然我放置了5个cube,但是drawcalls依然只有3。
正在上传…重新上传取消 1.4 减少实时光照和阴影效果 当开启灯光,在没有开启阴影的时候drawcalls为3,开启了之后drawcalls变成了7。实时阴影会导致drawcalls大幅上升,建议关闭实时阴影,使用lightmap满足你想要的阴影效果。
1.5 合并Mesh和材质球 如果一个模型有2个或者以上的材质球的时候,drawcalls会直线上升,所以应该劲量将mesh和材质球合并成为一个,以减少drawcalls。如图所示我在一个测试cube中放置了3个material,这个时候drawcalls从3变成了10(和不同的material有关,每个material最低为1)。
1.6 渲染顺序调整 Unity的渲染是有顺序的,这个顺序我们可以自己调整,相机按照深度进行渲染。在图中我使用了3个cube梯次排序,其中第一个和第三个使用相同的材质球。当第二个cube在中间时,drawcalls为5,第二个cube在前或者后时,drawcalls为4。
出现图中情况的原因是在绘制第一个cube时候使用材质球A,绘制第二个cube的时候使用材质球B,绘制第三个cube的时候使用材质球A,这个时候第二个打断了材质球A的渲染使用,使第一个和第三个材质球分开渲染了。
本人实测有效的方法:
用管理员身份打开
C:\Windows\System32\drivers\etc\hosts 或者用vscode打开,保存的时候会提示你用管理员身份重试。
在这个文件的末尾添加一句
185.199.108.133 raw.githubusercontent.com 保存即可。
7.1.1 输入输出系统和I/O控制方式 主机如何与I/O设备进行交互? **I/O接口:**又称I/O控制器、设备控制器,负责协调主机与外部设备之间的数据传输。其实就是一块芯片。
I/O控制方式简介 scanf("%d",&c)这个输入语句具体是如何执行的呢?
首先CPU会通过控制总线发送一个读命令,告诉键盘我要读一个数据,然后通过地址总线指明要使用哪个I/O设备。键盘接受到数据后,会将数据放到数据寄存器中。但是CPU怎么知道键盘是否已经工作结束了呢,键盘输入结束后会将结束信号卸载状态寄存器中,表明自己已经输入完成了,然后CPU去查询这个状态寄存器,就能够知道结束了没,然后就去数据寄存器中取数据然后赋值给c这个变量。
CPU如何控制键盘I/O的完成?
程序查询方式:CPU不断轮询检查I/O控制器中的状态寄存器,检查到状态为”已完成“之后,再从数据寄存器取出输入数据。不难得知,这种方式会极大地浪费CPU的资源,如果键盘一直不输入,CPU就会一直等待键盘输入而不能去做其他事情。**程序中断方式:**等待键盘I/O时CPU可以先去执行其他程序,键盘I/O完成后I/O控制器向CPU发出中断请求,CPU响应中断请求,并取走输入数据。这种方式就解决了CPU忙等的问题。 数据流:键盘-> I/O接口的数据寄存器->数据总线->CPU某寄存器->主存(变量的地址)
但是如果数据量很大的时候,没输入一个数据都会产生一次中断,这样CPU的大量时间都用来处理中断了,造成CPU的利用下降。
DMA控制方式 DMA控制方式:主存与高速I/O设备之间有一条直接数据通路(DMA总线)。CPU向DMA接口发出"读/写”命令,并指明主存地址、磁盘地址、读写数据量等参数。
DMA控制器自动控制键盘与主存的数据读写,没完成一整块数据读写,才向CPU发出一次中断请求。
主存地址:读/写的数据存在内存中什么位置
磁盘地址:从磁盘的什么位置开始读/写
读写数据量:要读/写多少信息。
通道控制方式 有的商用中、大型机可能会街上超多的I/O设备,如果都让CPU来管理,那么CPU就太累了。
所以为了出现了通道控制方式。
通道:是一种特殊的处理器,通道可以识别并执行一系列通道指令。
通道控制方式的执行:
CPU向通道发出I/O指令。指明通道程序在内存中的位置,并指明要操作的是哪个I/O设备。CPU就可以去做其他事情。通道执行内存中的通道程序,控制I/O设备完成一系列任务。通道执行完规定的任务后,向CPU发出中断请求,之后CPU对中断进行处理。 DMA是每处理完一次数据块后就执行一次中断,而通道是全部数据处理完后才向CPU发出中断。
I/O系统基本组成 一般来说,I/O系统由I/O软件和I/O硬件两部分组成。
I/O硬件:包括外部设备、I/O接口、I/O总线等。
7.2 I/O接口 I/O接口的功能 数据缓冲:匹配CPU与外部设备的速度差距。状态检测:反映外部设备的工作状态。格式转换:实现数据格式转换或逻辑电平信号转换。设备寻址:接收来自总线的地址信息,经过译码电路,选择对应外部设备中的寄存器或存储器。数据交互:实现外部设备、主存与CPU之间的数据交换。设备控制:传送CPU命令。 I/O接口的结构 **数据缓冲寄存器:**用于缓冲数据,以匹配CPU与外部设备之间的速度差异。
**设备状态寄存器:**用于反馈设备状态,常见的状态信息入设备忙、设备就绪、设备错误等。供CPU查用。
**设备命令寄存器:**用于接收CPU发送的设备控制命令
I/O接口的工作原理 发命令:发送命令字到I/O控制寄存器,像设备发送命令(需要驱动程序的协助)读状态:从状态寄存器读取状态字,获得设备或I/O控制器的状态信息读写数据:从数据缓冲寄存器发送或读取数据,完成主机与外设的数据交换。 设备控制器中的每个寄存器可以称为一个端口,
I/O端口及其编址 统一编址:把I/O端口当作存储器的单元进行地址分配,用统一的访存指令就可以访问I/O端口,又称 存储器映射方式。
靠不同的地址码区分内存和I/O设备,I/O地址要求相对固定在地址的某部分。
优点:不需要专门的输入/输出指令,所有访存指令都可直接访问端口,程序设计灵活性高。端口有较大的编址空间。读写控制逻辑电路简单。
缺点:端口占用了主存地址空间,使主存地址空间变小,外设寻址时间长(地址位数多,地址译码速度慢)
独立编址:I/O端口地址与存储器地址无关,独立编址CPU需要设置专门的输入/输出指令,又称I/O映射方式。是靠不同的指令区分内存和I/O设备。
7.3.1 程序查询方式 模拟:打印三个字符
先将要打印的数据存放到CPU的寄存器中,然后去查询打印设备的IO控制器中的状态寄存器,检查该设备此时是否准备就绪,如果不是则继续查询,否则就启动设备,然后将打印设备的地址通过地址线传送到地址译码器,然后将写命令通过控制线传送到I/O逻辑中,I/O逻辑会将该命令存到控制寄存器中。然后再将字符通过数据线传送到数据缓冲寄存器中,然后CPU的工作就完成了,但是他要一直查询状态寄存器的状态,查看设备是否已经打印完成,如果打印完成就继续下一个操作。I/O控制器将控制寄存器中的命令告诉打印设备,然后将数据缓冲寄存器中的数据送到该设备,设备完成之后就会将打印完成的状态告诉I/O逻辑。这样打印一个字符就算完成了。
慢速设备(比如鼠标):使用程序查询方式对CPU的工作影响不大
快速设备(比如硬盘):使用程序查询方式对CPU影响极大,CPU需要花费大量的时间去检查。
程序查询方式分为两种:
定时查询:每个一段时间去查询一次独占查询:一直不停地查询 7.3.2 中断的作用和原理 请解释一下中断(Interrupt)。
中断是一种计算机机制,用于在计算机执行期间暂停当前任务并转而处理某个特定事件。它可以是硬件引发的(如输入输出请求)或软件引发的(如异常处理)。 程序中断是指在计算机执行现行程序的过程中,出现某些继续处理的异常情况或特殊请求。CPU暂时中止现行程序,而转去对这些异常清理或特殊请进行处理,在处理完毕后CPU又自动返回到现行程序的断点处,继续执行原程序。
中断流程:
中断请求:中断源向CPU发送中断请求信号中断响应:响应中断的条件。中断判优:如果有多个中断,还要看优先处理哪一个。中断处理:中断隐指令。中断服务程序。 CPU执行完一条指令后,会去判断是否有中断信号,如果此时处于关中断,则不会去处理那些中断信号。那CPU是如何判断是否处于关中断呢?
关中断会被存放在CPU的状态寄存器中。
中断请求标记 CPU检测到了中断,那又是如何判断是哪个设备发来的中断信号?
每个中断源向CPU发出中断请求的时间是随机的。
为了记录中断时间并区分不同的中断源,中断系统需对每个中断源设置 中断请求标记触发器。
当其状态为 1 时,标识中断源有请求。
首先参考下面这篇文章:
layui form表单下的button按钮会自动提交表单的问题以及解决方案_layui form里面其他button按钮_你用点心就行的博客-CSDN博客
他说的已经很清楚了,我再补充(啰嗦)一下:
其实就是使用form的时候,应该对应有一个提交按钮,配套使用。其他功能按钮相加多少就加多少,但是必须要有一个提交按钮。
layui的官网说的也是比较清楚的,通过给按钮button加上“lay-submit”属性来表示它作为一个提交按钮,标准写法如下:
<button class="layui-btn" lay-submit lay-filter="demo-submit">提交按钮</button> <button class="layui-btn" id="test-btn-other">普通按钮</button> 官方文档地址:
表单组件 form - Layui 文档 因此,当我们在使用form的时候,如果没有添加标准的提交按钮,会自动默认把其他的普通按钮认为是提交按钮,因为button的type默认值为“submit”。
使用时注意:
1.在form中使用button时添加type属性:button、submit、reset;
2.在不需要提交的场景使用form时尽量使用a标签按钮来代替button,比如筛选功能中的查询按钮;
3.在form中使用了添加lay-submit属性的button时,尽量加上监听事件防止默认提交:
form.on('submit(formDemo)',function(data){ ...... return false; });
1. 静态代理 2.动态jdk代理 3.spring注解代理 1.静态代理
接口类:
实现类:
代理类:
总结:注入对象,代理方法;缺点:接口的所有方法都需要写一遍,有多个方法时重复多;
2.Jdk代理
代理类:
用例:
总结:内部类实现方法实现,优点:可以指定实现特定方法;
3.spring注解代理
代理类:
4.Spring Aop5种代理通知的写法: 1.前置通知
@Before("method()")
public void doBeforeAdvice(JoinPoint joinPoint){
System.out.println("我是前置通知!!!");
}
2.后置通知
@After("method()")
public void returnAfter(JoinPoint joinPoint){
System.out.println("我是后置通知!!!");
}
3.返回后通知
@AfterReturning(value="method()",returning = "result")
public void afterReturning(JoinPoint joinPoint,Object result){
System.out.println("我是返回后通知!!!返回值是:"+result);
}
4.异常通知
@AfterThrowing(value = "method()",throwing = "ex")
public void afterThrowing(JoinPoint joinPoint,Exception ex){
System.out.println("我是异常通知!!!异常是::"+ex);
}
5.环绕通知
@Around(value = "method()")
public Object aroundLogging(ProceedingJoinPoint joinPoint){
System.out.println("我是环绕通知");
joinPoint.proceed(); //调用目标方法
System.out.println("我是环绕通知");
一. 前言 本文以一个动态库编译的Makefile作为实例,讲解make中的静态模式规则的使用,加深对Makefile全方面的学习,达到学以致用的目的。
二. 静态模式规则 1. 语法
TARGETS ...: TARGET-PATTERN: PREREQ-PATTERNS ... COMMANDS ... 从上面的语法规则可以看出,静态模式规则包含三部分:TARGETS,TARGET-PATTERN和PREREQ-PATTERNS。
TARGETS:列出此规则的一系列目标文件,可以包含通配符。
TARGET-PATTERN:目标模式。一般会包含"%",其中"%"可以匹配目标文件中的任何部分,匹配的部分称为"茎",此外,目标文件和目标模式的其余部分必须精确的匹配,例如:
目标文件:foo.o
目标模式:%.o
茎:foo -> 模式符合
目标文件:foo.c
目标模式:%.o
茎:无 -> 模式不符合
PREREQ-PATTERNS:依赖模式。每个目标的依赖文件使用目标模式的"茎"代替依赖模式中的"%"而得到。举例如下:
目标文件:foo.o
目标模式:%.o
目标依赖:%.c
根据目标文件foo.o和目标依赖%.o,由上面介绍可以得出,"茎"是"foo",所以目标依赖%.c中%可以替换为foo,所以目标依赖就是foo.c了。
2. 举例
objects = foo.o bar.o all: $(objects) $(objects): %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ 根据上面语法的解释可知:该Makefile的目标文件是foo.o bar.o,目标模式是%.o,目标依赖是%.c。根据目标文件和目标模式,得出"茎"是foo和bar,所以目标模式时foo.o和bar.o,目标依赖是foo.c和bar.c。所以,相当于如下规则:
foo.o : foo.c $(CC) -c $(CFLAGS) foo.c -o foo.o bar.o : bar.c $(CC) -c $(CFLAGS) bar.c -o bar.o 二.
开发规范中要求:
【强制】不得使用外键与级联,一切外键概念必须在应用层解决。
原因使用数据库外键有以下缺点:
1.外键的性能问题 我刚写了一些,然后发现有人写的更好而且简洁,就引用吧:@mysqlops
为何说外键有性能问题: 1.数据库需要维护外键的内部管理; 2.外键等于把数据的一致性事务实现,全部交给 数据库服务器完成; 3.有了外键,当做一些涉及外键字段的增,删,更新操作之后,需要触发相关操作去检查,而不得不消耗资源; 4.外键还会因为需要请求对其他表内部加锁而容易出现死锁情况; 作者:mysqlops 链接: 大家设计数据库时使用外键吗? - 知乎 来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 总的来说物理外键是个比较“重”的实现,他会不顾性能不分轻重缓急的给你保证一致性。
2.mysql的外键设计问题 虽然很多人都不推荐你在关系型数据库使用外键。 但你更多听到的是mysql的,而不是SQLserver或者其他。比较公认的是,他的外键设计得的确不是很好,限制多功能不强大等,以innodb 为例子,包含但不限于以下几点(我认为比较严重的)
所有tables必须是InnoDB型,它们不能是临时表。在引用表中,必须有一个索引,外键列以同样的顺序被列在其中作为第一列。这样一个索引如果不存在,它必须在引用表里被自动创建。不支持对外键列的索引前缀。这样的后果之一是BLOB和TEXT列不被包括在一个外键中,这是因为对这些列的索引必须总是包含一个前缀长度InnoDB不对那些外键或包含NULL列的被引用键值检查外键约束 详细参考:mysql的外键约束 - Johney - 博客园
印象中轮子哥
@vczh
在回答一个跟存储过程有关的问题提到过,其他数据库不建议使用存储过程那是因为他们设计的不好,银行内不都比较推荐甚至要求sqlserver使用存储过程么(你没骗我吧)。反正我以前也是用sqlserver的,我觉得是挺好的。
3.外键对拓展性的限制和影响 外键的主从关系是定的,然后你会遵守这个规矩去干活。但是计划赶不上变化,万一哪天主键所在表需要拆分了呢?需要重构了呢?万一哪天你突然发现外键表不是非得跟主表的主键挂上关系呢?就我经历过的来看,这种情况并不少见,尤其是数据库设计者水平不够高的情况下。
另一方面,数据库帮你保证级联关系,你平时写程序的时候就真的思路清晰吗?因为某些原因(比如你想要的关系数据库不支持,mysql经常),有些地方你就不能设计外键了,当有级联更新的需要时,一部分靠物理外键,一部分还得靠自己,我觉得还不如全靠代码逻辑去保证。即使你对业务理解深刻,对外键也掌握的透彻,你也不太希望老是你管一部分他管一部分吧?
再放个大招,当你需要分库分表的时候,外键就浮云了。
4.逻辑外键在业界比较成熟 外键是个好东西,不使用物理外键,我们也可以约定逻辑外键(不在数据库声明FK,在程序实现上表达关联)
数据库上的策略:可以选择大多数情况下我们只更新不删除,也就是逻辑删,不再使用的历史数据定期归档来减少压力。
代码的设计和限制:对表范围的操作权限,开启事务去处理逻辑,有需要进行异步操作来提高性能的我们设计补偿机制去弥补,等等。
有人问原本在物理外键的开销,在程序上不也有开销吗。但是这样我们对优化性能的方式也灵活了,刚刚说的异步处理就是一种。视具体情况而定,如果设计的好,有时候某些“脏数据”你不是非得立刻删除他,甚至不是非得删除他。对于正确性>性能的说法,如果逻辑复杂到一定程度,物理外键一定能给你提供正确性吗?这个可以讨论讨论。
作者:justabug
链接:https://www.zhihu.com/question/39062169/answer/156096473
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
vim支持3种方法跳转到指定行位置:
1、vim filename +n行号(打开文件后,直接跳转到文件的第n行,强烈推荐这种)
2、ngg/nG (跳转到文件第n行,无需回车)
3、:n (跳转到文件第n行,需要回车)
TensorFlow的安装 anaconda的安装
版本信息:
1.1 文件下载
清华大学镜像库:https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/
1.2 安装路径:E:\Anaconda3.4
1.3 工作路径的修改
1.3.1 安装目录如下:
1.3.2 去掉%USERPROFILE%
1.3.3 生成配置文件jupyter_notebook_config.py
1 进入当前Anaconda安装位置(cmd),命令jupyter notebook --generate-config
2 打开jupyter_notebook_config.py,修改c.NotebookApp.notebook_dir = ‘D:\AnacondaNotebook’
修改后的工作目录:D:\AnacondaNotebook
1.4 修改国内镜像源
清华镜像源地址:https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
1.4.1 打开Anaconda Prompt,添加清华源
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/
1.4.2 设置搜索显示通道
conda config --set show_channel_urls yes
1.4.3 用户目录中找到。Condarc(配置文件),去点里面的 --defailt
查看当前的config
conda config --show
查看当前的添加的镜像
conda config --get channels
删除当前的源
conda config --remove-key channels
暂时下载:pip install tensorflow -i https://pypi.
qt加载dll有四种方式
本例中qt的版本为qt5.11.3 64位
一、动态加载 使用c++的函数,动态加载 bool bRet = false; HINSTANCE hDll = nullptr; hDll = LoadLibraryA("dlfs.dll"); if(hDll != nullptr) { bRet = true; } 二、使用qt自带的QLibrary进行加载 bool bRet = false; QLibrary liba("dlfs.dll"); if(liba.load) { bRet = true; } 三、静态加载 在pro中添加 lib include 有两种方式
(一) 手动 以配置opencv为例,在pro中直接填写如下内容即可
INCLUDEPATH += $$PWD/3rdparty/opencv/2.4.3/include/ INCLUDEPATH += $$PWD/3rdparty/opencv/2.4.3/include/opencv/ INCLUDEPATH += $$PWD/3rdparty/opencv/2.4.3/include/opencv2/ LIBS += -L$$PWD/3rdparty/opencv/2.4.3/x64/lib/ -lopencv_core243d (二)自动 项目-----添加库---外部库-- 选择 库文件 和 库路径 点击确定后即 在pro中生成如下的内容。
也可以不按照此步骤,直接在pro中添加如下的代码即可
最后在pro中生成的为: INCLUDEPATH += $$PWD/3rdparty/opencv-4.
VS2019安装(入门新手向) 1. 下载VS20192. 安装VS20193. 测试VS2019(以C语言为例)4. 安装包备份 官网现在只显示VS2022的安装,VS2022可能不太稳定。本文记录现如今VS2019的下载安装方式。 安装版本:Visual Studio Community 2019【该版本免费】简称VS2019
VS2017、VS2015、VS2013、VS2012下载和安装也都可以参考本文
1. 下载VS2019 进入Visual Studio官网点击右上角的搜索按钮搜索VS2019,点击下图所示的链接。也可以直接进入网站 Visual Studio 较旧的下载将页面划到下面,点击2019,然后点击下载找到 Visual Studio Community 版本,该版本为社区版,是唯一免费的版本如果你的电脑为32位的,要将x64改为x86,然后再下载。
不清楚电脑是32位还是64位的可以右击桌面上的此电脑图标,点击属性,可以从系统类型这边来确定下载好后的图标如下 2. 安装VS2019 打开下载好后的VS2019文件点击“继续”按钮等待准备就绪选择VS2019安装的内容,我用VS2019主要为了C语言和C++,所以选择使用C++的桌面开发,右下角为安装的大小如果想要更改安装位置,可以点击安装位置,进行修改,本文安装时采用默认安装位置,所有不用进行更改,直接点击右下角的“安装”按钮接下来等待下载和安装安装完成后需要重启电脑即可,如果没有微软账号的需要注册一个。 3. 测试VS2019(以C语言为例) 打开VS2019,选择创建新项目选择空项目,点击下一步对项目名称和项目位置进行配置,这边只是测试,所有采用默认的即可进去后,右击“源文件”,点击“添加”,点击“新建项”选择C++文件,文件名称随意,也可以如本文的test,将后缀改为.c【因为是C语言测试】在代码区输入如下代码来进行测试(也可以直接复制下文的代码),按住Ctrl按键后拨动鼠标的滑轮来进行代码区的放大缩小,直到代码大小合适为止 #include <stdio.h> int main() { printf("Hello World!"); return 0; } 按住Ctrl+F5运行代码,在控制台显示Hello World!的字样,即安装、运行成功【你的控制台可能是黑底的,不过没有影响】 4. 安装包备份 进入该仓库VS2019 64位社区版注册一个账号并登录点击克隆/下载点击下载ZIP通过机器验证即可下载VS2019 的64位社区版安装包
今天,我们很高兴地宣布在 Visual Studio 17.7 预览版中推出可视化宏扩展功能。这个新功能通过可视化的方式对宏代码进行逐步扩展。
若要开始使用此功能,请确保你的 Visual Studio 版本更新到最新版本的 Visual Studio 预览版。
下面,我们来看看这个新玩意儿!
可视化宏扩展 在现有版本的 Visual Studio 中已经引入了增强的宏扩展功能。此功能带来了显著的好处,使你能够逐步理解和查看复杂的多级宏扩展。将鼠标悬停在宏上时,可以访问”快速信息”,除了”复制”和”展开内联”选项外,现在还包括”可视化展开”链接。可视化扩展将使你能够可视化扩展的预处理器传递。
>> 请移步至 topomel.com 以查看图片 <<
“可视化展开”链接将打开一个新窗口,最初显示宏展开的第一步。通过使用扩展步骤编号旁边的箭头,你可以轻松浏览扩展的后续步骤。此功能在涉及具有冗长扩展的嵌套宏的方案中特别有价值。在嵌套宏具有较长扩展的情况下,此功能将有助于精确识别每个步骤中发生的操作,从而有助于更深入地了解宏的行为。最终,此功能大大提高了调试工作的效率,使你能够更有效地查明和解决问题。
>> 请移步至 topomel.com 以查看图片 <<
总结 “你呀,总能给我整出点新花样。”
最后 Microsoft Visual C++团队的博客是我非常喜欢的博客之一,里面有很多关于Visual C++的知识和最新开发进展。大浪淘沙,如果你对Visual C++这门古老的技术还是那么感兴趣,则可以经常去他们那(或者我这)逛逛。
本文来自:《Visualize Macro Expansion for C++》
[RC-04] 01 背包
题目描述
有一个容积为无穷的背包,你要往里面放物品。
你有 n个物品,第 i 个体积为 ai。
你有一个幸运数字 p,若放入的物品体积和为 k,你会得到 p^k$的收益。特别地,0^0=1。
求所有 2^n 种放入物品的方案的收益和。答案很大,因此请输出它对 $998244353$ 取模的值。
输入格式
第一行两个整数 n,p。
接下来一行 n 个正整数 a1~an,描述这 n 个物品的体积。
## 输出格式
输出一个整数,为所有 2^n 种方案的收益和对 998244353 取模的值。
样例输入 1
```
2 2
1 4
```
样例输出 1
```
51
```
//对于第i个物品都有两个选择 ,选择,则它的贡献就是乘上p^ai;不选,则它的贡献就是1
经过总结得
答案为 (p^a1+1)*(p^a2+1)*(p^a3+1)*(p^a4+1)*(p^a5+1)*……(p^an+1)
在求p^ai%mod时,可以使用快速幂进行计算
#include <bits/stdc++.h> using namespace std; #define int long long const int N=1e6+10; const int mod=998244353; int qmi(int a,int k,int p) //快速幂 { int ans=1; while (k) { if (k&1) ans=ans*a%p; k >>=1; a=a*a%p; } return ans; } signed main() { int n,p; cin>>n>>p; int sum=1; for (int i=1;i<=n;i++) { int x; cin>>x; sum=sum*(qmi(p,x,mod)+1)%mod; //公式 } cout<<sum; return 0; }
沙盒安装 1、打开控制面板
2、选择程序与功能
3、勾选Windows 沙盒,然后点击确定,等待安装完成即可。
沙盒配置 Windows 沙盒支持简单的配置文件,这些文件为沙盒提供最少的自定义参数集。 此功能可与 Windows 10 内部版本 18342 或 Windows 11 一起使用。 Windows 沙盒配置文件的格式为 XML,并通过.wsb文件扩展名与沙盒相关联。
配置文件使用户能够控制Windows 沙盒的以下方面:
vGPU (虚拟化 GPU) :启用或禁用虚拟化 GPU。 如果禁用 vGPU,沙盒将使用 Windows 高级光栅化平台 (WARP) 。网络:启用或禁用沙盒中的网络访问。映射的文件夹:共享具有 读取 或 写入 权限的主机中的文件夹。 公开主机目录可能会允许恶意软件影响系统或窃取数据。登录命令:Windows 沙盒启动时执行的命令。音频输入:将主机的麦克风输入共享到沙盒中。视频输入:将主机的网络摄像头输入共享到沙盒中。受保护的客户端:将 RDP 会话上增加的安全设置置于沙盒中。打印机重定向:将打印机从主机共享到沙盒中。剪贴板重定向:与沙盒共享主机剪贴板,以便可以来回粘贴文本和文件。内存(MB):要分配给沙盒的内存量(以 MB 为单位)。 备注: 沙盒窗口的大小目前不可配置。
创建配置文件 若要创建配置文件,请执行以下操作:
打开纯文本编辑器或源代码编辑器 (例如记事本、Visual Studio Code等)
插入以下行:
<Configuration> </Configuration> 在两行之间添加适当的配置文本。 有关详细信息,请参阅正确的语法和以下示例。
使用所需名称保存文件,但请确保其文件扩展名为 .wsb。 在记事本中,应将文件名和扩展名括在双引号内,例如: "My config file.wsb"。
使用配置文件 若要使用配置文件,请双击它以根据其设置启动Windows 沙盒。 还可以通过命令行调用它,如下所示:
C:\Temp> MyConfigFile.wsb 关键字、值和限制 vGPU 启用或禁用 GPU 共享。
在windows10安装xmanager完整版,一定要有xmanager xstart 和xmanager-pasiive 如图所示。
需要免费安装包的关注我后给我评论区留言。
关键技术分享防止踩坑,可为您节约大量时间。
使用步骤:
1安装xmanager完整版
2打开xstart
3,敲黑白:设置display的环境变量是在windows里已运行的shell终端里设置,而不是在远程主机里设置。如图所示:
另外我在此遇到的问题:输入一个字符会出现两个同意的字符。解决方案
1,
2,
3,
4,建议把自动复制粘贴关闭