首页
烟花
归档
随笔
聚合
部落格精华
部落格资讯
CSS教程
CSS3教程
HTML教程
HTML5教程
建站经验
网站优化
资讯
今日早报
资讯日历
科技新闻
今天
罗盘
网盘
友链
留言
1
「今日早报」 2025年5月11日, 农历四月十四, 星期日
2
「今日早报」 2025年5月10日, 农历四月十三, 星期六
3
「今日早报」 2025年5月9日, 农历四月十二, 星期五
4
「今日早报」 2025年5月8日, 农历四月十一, 星期四
5
「今日早报」 2025年5月7日, 农历四月初十, 星期三
沙漠渔
把過去的累積,善用到當下
累计撰写
2,465
篇文章
累计创建
385
个标签
累计收到
994
条评论
栏目
首页
烟花
归档
随笔
聚合
部落格精华
部落格资讯
CSS教程
CSS3教程
HTML教程
HTML5教程
建站经验
网站优化
资讯
今日早报
资讯日历
科技新闻
今天
罗盘
网盘
友链
留言
搜索
标签搜索
代理服务
winsw
override
VMware
api
popai
拉取镜像
人工智能
copilot
chatgpt
openai
coze
objdump
ldd
日志
版本
latest
批处理
bat
节能模式
iwconfig
排序
du
设计模式
hostname
面板
cockpit
版本不兼容
npm
统计
烟花
新春
leveldb
Java heap space
堆内存
harbor
utf8mb4
网络聚合
IPV6
nmtui
测速
带宽
千兆
路由器
nmcli
nmlci
orangepi
motd
中文乱码
webdav
香橙派
代码折叠
享元模式
单例模式
解锁
锁定
无法安装
Xshell
并发编程
ScheduledThreadPoolExecutor
ThreadPoolExecutor
线程池
Fock-Join
并发
ExecutorService
nextcloud
alist
panic
hung task
时间戳
ping
tail
dd
嵌入式
点灯
mount
共享
NFS
curl
全屏
ChannelOption
C++
comparator
桥头堡
开源
varchar
char
StringBuilder
StringBuffer
String
命令行工具
网络配置
netsh
建议
专家
离谱
2022
设备管理器
虚拟网卡
环回适配器
安全
攻击
CC
DDOS
跳槽
过年
年假
春节
2023
优站计划
鼻塞
咳嗽
大号流感
阳
新冠病毒
循环冗余校验
CRC-16/XMODEM
crc校验
stream
DMZ主机
域名解析
CDN
七牛云
DDNS
类加载器
双亲委派
加载机制
删除
搜索
变化时间
修改时间
访问时间
响应异常
超时
jsoup
用法详解
压缩命令
打包压缩
zip
优缺点
打包
数据压缩
密码
sudoers
索引量
权重
瞬间
魔鬼洞
沙漠鱼
沙漠渔
面试
引用传递
值传递
即时编译器
机器码
JIT
旗舰版
ISO
原版镜像
win7
参数
配置文件
8小时
时间错误
报告
coverity
jetbrains
idea
谷歌翻译
rest
403
ERR_UNKNOWN_URL_SCHEME
DevTools
优先级
location
FTP
挂载
curlftpfs
提示
自定义参数
springboot
配置
死锁
超级密码
桥接
联通光猫
Dockerfile
构建
命令行
eclipse
光猫
路由模式
桥接模式
bash-4.2
sudo
oracle帐号
JDK下载
百度收录
定时发布
哨兵模式
内存管理
JVM
登录
免密
不一致
服务器时间
BIO,NIO,AIO
ByteBuffer
FileWriter
BufferedOutputStream
流水线
pipeline
环境变量
重启
任务消失
jenkins
卸载
snap
20.04
Ubuntu
容器
大数据传输
InputStream
学习笔记
CSS
最佳实践
DOM操作
原型链
原型
No such file or Directory
SSH配置
SSH免密
tar
命令
网站优化
取消快照
百度快照
全局配置
修改密码
控制台
gitlab
解码器
Netty
文件传输
sz
rz
Jar
打铁花
羊毛沟
容器日志
docker
规范
博客
rejected
Gerrit
wireshark
代理
Go
http-server
nodejs
package-lock.json
996加班
删除标签
钟薛高
60s新闻接口
每日新闻接口
百度福利
自动回复
localstorage
QQ机器人
redis
近乎
客户端
JuiceSSH
乔恩
加菲猫
新浪邮箱
joe
公告
父亲节
图标
每日新闻
51la
服务器
腾讯云
插件
罗永浩
编码
avatar
小虎墩大英雄
端午劫
端午节
中石化
中国石化
儿童节
win10
激活
shell
金门大桥
旧金山
产品经理
免疫力
熬夜
云旅游
云游
招聘
海尔
halo
校友会
创新
哈工大
鸿蒙
王成录
标题
主题
北京
疫情
域名
沙漠渔溏
方法声明
jpa
表情包
emoji
JavaAgent
姓名测试
姓名打分
起名
百度
收录
SEO
group by
distinct
去重
JDBC
validationQuery
兄弟元素
点击事件
$event
9600
传输延时
波特率
串口
站点统计
站长工具
cnzz
生命周期
refs
vue
replaceAll
replace
JavaScript
软件
FRP
内网外入
内网穿透
学习
解题
leetcode
云计算
中国医药
神思电子
股票
Java
报错
数据块
关键词
风筝
清明节
注解
spring
clang-format
格式化
反向代理
nginx
索引
linux
vim
数据库
仓库管理
git
压缩
winrar
mysql
测试
markdown
目 录
CONTENT
以下是
网络聚合
相关的文章
2024-01-19
『网络聚合』 虚拟DOM
一、对虚拟DOM的理解 虚拟DOM就是用来描述真实DOM的javaScript对象,可以将多次修改的DOM一次性渲染到页面上,减少页面的重排重绘,提高渲染性能 虚拟DOM就是用来描述真实DOM的javaScript对象,可以将多次修改的DOM一次性渲染到页面上,减少页面的重排重绘,提高渲染性能。 在代码渲染到页面之前,vue会把代码转换成一个对象(虚拟 DOM)。在每次数据发生变化前,虚拟DOM都会缓存一份,变化之时,现在的虚拟DOM会与缓存的虚拟DOM进行比较。在vue内部封装了diff算法,通过这个算法来进行比较,渲染时修改改变的变化,原先没有发生改变的
2024-01-19
214
0
0
网络聚合
2024-01-19
『网络聚合』 .NET 7新特性
2022年11月份微软推出了带有STS(标准期限支持)的.NET版本7,仅提供18个月的支持。 微软今年推出了STS版本,因为它已经在2019年提到,它将在每年11月左右发布一个新版本的.NET。 但是,考虑到新的官方.NET7功能和更新,它仍然为用户带来了大量变化和.NET7性能改进。今天给大家分享.NET 7与.NET 6之间的几个值得注意的差异如下: 一、On-stack replacement(OSR) 允许在执行过程中更改已执行的代码。我们可以对于长时间正在运行的方法在执行过程中转换到更新的版本。 堆栈替换背后的思想是,方法不仅可以在调用之间进行替换,甚至可
2024-01-19
327
0
0
网络聚合
2024-01-19
『网络聚合』 Cryptanalyzing and Improving a Novel Color Image Encryption Algorithm Using RT-Enhanced Chaotic Tent Maps
Cryptanalyzing and Improving a Novel ColorImage Encryption Algorithm Using RT-EnhancedChaotic Tent Maps 基于RT增强混沌帐篷映射的彩色图像加密算法 文章信息 博客内容仅用于学习。 CONGXU ZHU 1,2,3 AND KEHUI SUN4 1School of Information Science and Engineering, Central South University, Changsha 410083, China 2Guangxi
2024-01-19
256
0
0
网络聚合
2024-01-19
『网络聚合』 轮播图接口加缓存和定时更新(双写一致性问题以及其解决方案)
一、轮播图加缓存 有些知名网站首页被访问的频率很高,假设瞬间 1w个人在访问,首页的轮播图接口会执行1w次,1w次查询轮播图标的sql在执行,轮播图基本不变,首先我们给自己写的轮播图接口加缓存,我们可以用缓存数据库Redis来实现加缓存的需求 首先罗列一下文字版的逻辑,之后在代码上实现 当轮播图接口来了请求 先去缓存看看,如果有缓存,直接返回 如果没有缓存,则去数据库查询 然后拿到数据放到Redis中,缓存起来 通过代码实现加缓存 from rest_framework.viewsets import GenericViewS
2024-01-19
271
0
0
网络聚合
2024-01-19
『网络聚合』 springcloud-gateway整合jwt+jcasbin实现权限控制
jcasbin简介: jcasbin 是一个用 Java 语言打造的轻量级开源访问控制框架https://github.com/casbin/jcasbin,是casbin的Java语言版本。目前在 GitHub 开源。jcasbin 采用了元模型的设计思想,支持多种经典的访问控制方案,如基于角色的访问控制 RBAC、基于属性的访问控制 ABAC 等。 jcasbin 的主要特性包括: 1.支持自定义请求的格式,默认的请求格式为{subject, object, action};2.具有访问控制模型 model 和策略 policy 两个核心概念;3.支持 RBAC 中的多层
2024-01-19
159
0
0
网络聚合
2024-01-19
『网络聚合』 红袖添香,绝代妖娆,Ruby语言基础入门教程之Ruby3基础语法,第一次亲密接触EP01
书接上回,前一篇我们在全平台构建好了Ruby3的开发环境,现在,可以和Ruby3第一次亲密接触了。 Ruby是一门在面向对象层面无所不用其极的解释型编程语言。 我们可以把编写Ruby代码看作是一场行为上的艺术,编码就像跳舞一样,Ruby的每一步都很优雅,几乎没有一步是多余的。 第一行代码 进入系统的irb终端,输入第一行代码: irb(main):001:0> puts "你好 Ruby!" 你好 Ruby! => nil puts关键字是 Ruby 语言里用来打印的基本命令。第三行输出的nil 是什么?其实是puts命令的返回值, puts
2024-01-19
230
0
0
网络聚合
2024-01-19
『网络聚合』 Golang HTTP编程及源码解析-路由分发
1、网络基础 基本TCP客户-服务器程序Socket编程流程如如下图所示。 TCP服务器绑定到特定端口并阻塞监听客户端端连接, TCP客户端则通过IP+端口向服务器发起请求,客户-服务器建立连接之后就能开始进行数据传输。 Golang的TCP编程也是基于上述流程的。 2、Golang HTTP编程 2.1 代码示例 func timeHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "%v", time.Now().Format(time.RFC3339)
2024-01-19
257
0
0
网络聚合
2024-01-19
『网络聚合』 互联网技术大佬独立博客推荐
1,bang's blog 17 年就是蚂蚁金服 P8 的前端大佬。博客质量基本都很高,看他的文章会让我得到些思考,比如文章中的 “心流”(我的叫法跟他的不一样,但内核一样)的描述,我之前也有过类似的状态,但只有一次,就是高三临场抱佛脚,花了 3 周让自己的排名进步了近 1000 名的复习经历,可惜这种状态太难得了,他首先需要的就是无与伦比的专注! 2,Guibo Wang blog 腾讯广告算法大佬的博客,我是通过他的《手撸一个简单深度学习框架》文章找到他的博客站的,网站文章数量不多,但是基本是高质量!作者部分博客文章截图如下: 3,yongyuan blo
2024-01-19
162
0
0
网络聚合
2024-01-19
『网络聚合』 在 SpringBoot 项目中简单实现 JWT 验证
使用 SpringBoot 提供 api 的时候,我更喜欢使用 jwt 的方式来做验证。网上有会多 Spring Security 整合 jwt 的,也有 Shiro 整合 jwt 的,感觉有点复杂。这里分享一下自己在项目中的简单实现。 依赖包 除了 SpringBoot 基本的依赖,需要一个生成 jwt 和序列化的包。生成 jwt 的包依赖很多,因为我项目里使用了 hutool 这个包,就只用用它了。 <dependency> <groupId>cn.hutool</groupId>
2024-01-19
209
0
0
网络聚合
2024-01-19
『网络聚合』 探索FSM (有限状态机)应用
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品。我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值。。 本文作者:木杪 有限状态机(FSM) 是计算机科学中的一种数学模型,可用于表示和控制系统的行为。它由一组状态以及定义在这些状态上的转换函数组成。FSM 被广泛用于计算机程序中的状态机制。 有限状态机(FSM)应用场景 在各种自动化系统的应用: 例如交通信号灯、地铁站的旋转闸门、银行自动取款机等。通过对状态和转换函数的定义,可以实现对系统行为的精确控制。 交通信号灯状态流转图 地铁站的旋转闸门状态流转图
2024-01-19
127
0
0
网络聚合
2024-01-19
『网络聚合』 React报错之Element type is invalid
总览 产生"Element type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got"错误有多个原因: 在导入组件时,将默认导入和命名导入混淆。 忘记从文件中导出组件。 不正确地定义了一个React组件,例如,作为一个变量而不是一个函数或类。 为了解决该错误,确保使用大括号来导入命名导出而不是默认导出,并且只使用函数或类作为组件。 这里有个示例来展示错误是如何发生的
2024-01-19
129
0
0
网络聚合
2024-01-19
自己动手从零写桌面操作系统GrapeOS系列教程——10.NASM汇编语言
学习操作系统原理最好的方法是自己写一个简单的操作系统。 汇编语法主要有两种:Intel语法和AT&T语法。 由于大部分介绍x86汇编的书籍和资料用的都是Intel语法,毕竟x86就是Intel发明的,大家学过的x86汇编大概率也是Intel语法,所以GrapeOS的汇编也用Intel语法。 支持Intel语法的x86汇编器不止一种,常见的有MASM和NASM。MASM来自微软公司,只能在微软的操作系统Windows和MS-DOS上用。NASM是开源软件,支持多平台。GrapeOS选用NASM。 下面介绍一下NASM在Linux上的使用 1.首次使用需要先安装 yum install nasm 由于我之前已经安装过了,所以在上面的截图上显示“无须任何处理”。本教程中后续用到的Linux命令如果提示没有,一般都通过 yum install命令安装即可。 2.使用NASM汇编器 我们以第5讲中的代码为例: nasm boot.asm -o boot.bin nasm 命令后面紧跟的boot.asm是汇编代码的源文件,参数-o后面跟的是生成文件的文件名。 从上面的截图我们可以看到生成了boot.bin文件。这里的boot.bin是一个二进制文件,里面就是生成的机器码。CPU只认识机器码。把这个文件中的内容给CPU,CPU就能执行。 下面我们补充一下如何查看二进制文件。 对于文本文件,Linux下可以使用cat命令查看,比如我们用cat命令查看boot.asm文件: 如果我们用cat查看二进制文件boot.bin: 从上面的截图中可以看到,用cat查看二进制文件会显示乱码。 在Linux中可以使用hexdump命令来查看二进制文件。 hexdump boot.bin 我们来看上面的截图,hexdump命令默认显示的是十六进制数。左边第一列是每一行数据在文件内的起始字节索引,右边其它列都是文件内的数据。文件内的数据每两个字节写在一起,高地址字节写在前面,低地址字节写在后面,一行共显示16个字节。在第5行下面一行只有一个星号“*”,表示相同的行重复若干行,直到遇到不同的行为止。星号上面一行都是0,这里星号表示重复了若干行0,直到最后一行数据不是全0。在最后一行数据下面一行有个数字,表示文件总字节数,这里是0x200,换算成十进制数是512。 在实际使用时可以加上一个参数-C: hexdump boot.bin -C 效果如下图: 从上面的截图可以更加清晰的看到文件中每个字节的十六进制数。此时右边多了一大列,用竖线包裹者的数据,里面很多是点号。其实这是同一行中的16个字节分别以ASCII字符显示的结果,ASCII中的不可显示字符在这里就都用点号代表了。我们用hexdump命令查看一个文本文件大家对比一下就明白了,下面以汇编源文件boot.asm文件为例。 hexdump boot.asm -C 从上面截图上可以看到,中间区域是文件中每个字节的十六进制数,右边竖线列中显示的就是每个字节对应的ASCII字符。 本讲对应的视频版地址:https://www.bilibili.com/video/BV1PT411X7VG/ GrapeOS操作系统交流QQ群:643474045
2024-01-19
305
0
0
网络聚合
2024-01-19
【论文笔记】UNet
语义分割的U-Net网络结构Unet是2015年诞生的模型,它几乎是当前segmentation项目中应用最广的模型。Unet能从更少的训练图像中进行学习,当它在少于40张图的生物医学数据集上训练时,IOU值仍能达到92%。Unet网络非常简单,前半部分作用是特征提取,后半部分是上采样。在一些文献中也把这样的结构叫做编码器-解码器结构。由于此网络整体结构类似于大写的英文字母U,故得名U-net。 论文链接: https://arxiv.org/pdf/1505.04597v1.pdf github: https://github.com/milesial/Pytorch-UNet 1 Motivation 生物医学图像处理面临的问题 经典卷积网络大部分都是针对图像分类任务的,但是在一些特定场景,如医疗图像处理领域,应是pixel-wise像素级的处理,输入输出均是图像,即图像分割。 生物医学任务中没有很多标注的数据集 为了解决这两个问题,Ciresan用滑窗法来预测patch的类别(patch指像素周围的局部区域)。 该算法有两个主要问题:(1)由于每个patch都需要训练导致这个算法很慢,且patch之间有很多重复。(2)定位准确率和上下文联系之间需要平衡,patch越大需要pooling越多准确率越低,patch越小则不具备上下文联系。 2 U-Net网络 作者以FCN全卷积神经网络为基础设计了Unet,其中包含两条串联的路径:contracting path用来提取图像特征,捕捉context,将图像压缩为由特征组成的feature maps;expanding path用来精准定位,将提取的特征解码为与原始图像尺寸一样的分割后的预测图像。 和FCN相比,U-Net的第一个特点是完全对称,也就是左边和右边是很类似的,而FCN的decoder相对简单,只用了一个deconvolution的操作,之后并没有跟上卷积结构。第二个区别就是skip connection,FCN用的是加操作(sum),U-Net用的是叠操作(concat)。最重要的是编码和解码(encoder-decoder)的思路,编码和解码常用于压缩图像和去噪声,后来这个思路被用在了图像分割上,非常简洁好用。 网络左边一侧作者称之为contracting path,右边一侧为expanding path。 蓝色箭头为卷积层,卷积层的stride=1,padding=0,因此卷积后特征层的宽高会减2。卷积层后接ReLU激活函数,没有BN层(BN由Google于2015年提出)。 池化层stride=2,池化后宽高减半,通道数不变。池化层之后的卷积层将通道数翻倍。 绿色的up-conv是转置卷积,将特征层的宽高×2,通道数减半。 灰色copy and crop是先对左边的特征层进行中心裁剪(保留中心特征),再与右边path对应的特征层进行通道数上的concat。 最后的1×1的卷积没有ReLU,输出通道数为类别数。 Overlap-tile 可以发现Unet论文中输入的图像是572×572,但是输出图像大小为388×388。也就是说推理上图黄色部分,需要蓝色区域内的图像数据作为输入。当黄色区域位于边缘时,就会产生边缘数据缺失的情况(上图右边蓝框中的空白部分)。我们可以在预处理中,对输入图像进行padding,通过padding扩大输入图像的尺寸,使得最后输出的结果正好是原始图像的尺寸,同时输入图像块(黄框)的边界也获得了上下文信息从而提高预测的精度,本文用的是mirror padding。我们自己搭建网络的时候,输入输出往往是一样大小的(padding=1),因此不需要考虑这个问题。 3 训练 3.1 数据增强 网络需要大量标注训练样本,生物医学任务中没有数千个标注的数据集,所以需要对数据进行数据扩张。作者采用了弹性变形的图像增广,以此让网络学习更稳定的图像特征。因为数据集是细胞组织的图像,细胞组织的边界每时每刻都会发生不规则的畸变,所以这种弹性变形的增广是非常有效的。论文笔记:图像数据增强之弹性形变(Elastic Distortions) 3.2 损失函数的权重 细胞组织图像的一大特点是,多个同类的细胞会紧紧贴合在一起,其中只有细胞壁或膜组织分割。因此,作者在计算损失的过程中,给两个细胞的边缘部分及细胞间的背景部分增加了损失的权重,以此让网络更加注重这类重合的边缘信息。 如上图所示,图(a)为原始图像,图(b)为人工标注的实例分割ground truth,图(c)为mask,图(d)为每个像素的损失权重weight map。首先用形态学操作获得边界,再用下面的公式计算weight map 其中,wc是为了类别平衡,d1是该像素到最近细胞边界的距离,d2是到第二近的细胞边界的距离。在作者实验中设置w0=10,σ≈5pixels. 3.3 其他 优化器:SGD + momentum(0.99) batch:为了最大限度的使用GPU显存,比起输入一个大的batch size,更倾向于大量输入tiles,因此实验batch size为1。 损失函数:pixel-wise softmax + cross_entropy 初始化高斯分布权重:在具有许多卷积层和通过网络的不同路径的深度网络中,权重的良好初始化非常重要。 否则,网络的某些部分可能会进行过多的激活,而其他部分则永远不会起作用。 理想情况下,应调整初始权重,以使网络中的每个特征图都具有大约单位方差。作者用的高斯分布的权重。 参考 1. 精读论文U-Net 2. 论文笔记:图像数据增强之弹性形变(Elastic Distortions) 3. 研习U-Net
2024-01-19
163
0
0
网络聚合
2024-01-19
浅谈 C++ 模板 & 泛化 (妈妈再也不用担心我不会用 std::sort 了)
基础复习 先上个对 int 类型数组的插入排序: void insertionSort_01(int* seq, int firstIndex, int lastIndex) { for (int j = firstIndex + 1; j <= lastIndex; ++j) { int key = seq[j]; int i = j - 1; while (i >= firstIndex && key < seq[i]) { seq[i + 1] = seq[i]; --i; } seq[i + 1] = key; } } 提出问题: 如果想排 double 类型数组怎么办? 可以重载一个 double 版本: void insertionSort_01_b(double* seq, int firstIndex, int lastIndex) { ... } 当然, 更好的方式是利用 C++ 的模板泛化元素类型: template<class ElemType> void insertionSort_02(ElemType* seq, int firstIndex, int lastIndex) { ... } 步入正题 接着提出两个问题: 1 是否一定要求升序排列 2 ElemType 对象是否一定能使用 operator< 为解决问题 1, 我们可以额外写个降序排列版本: template<class ElemType> void insertionSort_02_b(ElemType* seq, int firstIndex, int lastIndex) { for (...) { ... // Change {<} to {>} when comparing {key} and {seq[i]}: while (i >= firstIndex && key > seq[i]) { ... } ... } } 对于问题 2, 我们举个例子. 现有: struct MyStruct { int aa; int bb; }; MyStruct arr_MyStruct[4] = { {1,4},{3,1},{9,-1},{12,0} }; 要求对 arr_MyStruct 中的元素以 MyStruct::aa 排序. 对于 C++ 新手来说, 这是一个比较难解决的问题, 也是问题 2 聚焦的关键. 对问题 1 的处理中, 我们将 "比较" 这个谓语 (predicate) 从 operator< 替换为 opeartor>; 这给了我们一些提示: 是否可以像我们用模板来泛化元素类型那样泛化谓语? 提出概念: 函数对象 (function object) 定义类 bad_greater: // Omit the definition of class <MyStruct>. struct bad_greater { // {operator()} should be defined as a const method, // in order to make it available to <const bad_greater> instances. bool operator()(const MyStruct& left, const MyStruct& right) const { return left.aa > right.aa; } }; 称 bad_greater 所创建的实例为函数对象, 可以参考以下使用案例: // Omit the definition of class <MyStruct>. MyStruct arr_MyStruct[4] = { {1,4},{3,1},{9,-1},{12,0} }; bad_greater compare; std::cout << compare(arr_MyStruct[0], arr_MyStruct[1]) << std::endl; // Use anonymous instance: std::cout << bad_greater()(arr_MyStruct[0], arr_MyStruct[1]) << std::endl; bad_greater 之所以 bad, 是因为其唯独提供对类 MyStruct 实例的比较. 定义一个模板类 good_less 并对 MyStruct 偏特化以解决这个问题: // Omit the definition of class <MyStruct>. template<class T> struct good_less { bool operator()(const T& left, const T& right) const { return left < right; } }; template<> struct good_less<MyStruct> { bool operator()(const MyStruct& left, const MyStruct& right) const { return left.aa < right.aa; } }; 有了函数对象, 我们可以泛化算法中的谓语: template<class ElemType, class _Pred> void insertionSort_03(ElemType* seq, int firstIndex, int lastIndex, const _Pred& compare) { for (...) { ... while (... && compare(key, seq[i])) { ...; } ... } } 调用函数 insertionSort_03() 时, 我们要注意, 编译器能直接根据传入参数推断模板的实例化类型; 因此无需提供额外的模板类参数: // Omit the definition of class <MyStruct>. // Omit the definition of class <good_less>. // Omit the definition of class <good_greater>. MyStruct arr_MyStruct[4] = { {1,4},{3,1},{9,-1},{12,0} }; // Ascending order: insertionSort_03(arr_MyStruct, 0, 3, good_less<MyStruct>()); // Descending order: insertionSort_03(arr_MyStruct, 0, 3, good_greater<MyStruct>()); // Also works for array with orther types: double arr_double[4] = { 1,9.1,0.9,-3.1 }; insertionSort_03(arr_MyStruct, 0, 3, good_greater<double>()); std::sort() 的升降序排序 std::sort() 和我们的 insertionSort_03() 一样泛化的谓语, 而且 STL 还提供了类 std::greater 和 std::less 等用于定义函数对象. 升降序的使用方法参考以下代码: #include <algorithm> #include <functional> double arr_double[4] = { 1,9.1,0.9,-3.1 }; // Ascending order: std::sort(arr_double, arr_double + 4); // Ascending order: std::sort(arr_double, arr_double + 4, std::less<double>()); // Descending order: std::sort(arr_double, arr_double + 4, std::greater<double>())); 你可能会问: 为什么第一个例子不用和之前说的一样, 传入一个函数对象? 这没什么高深的, 在 C++14 之前, 其实只是额外提供了一个只有两个参数的函数重载而已. 给个差不多的伪代码出来: std::sort(seq_begin, seq_end){ std::sort(seq_begin, seq_end, std::less()); } C++14 之后在谓语类和 std::sort() 的定义上用了点小 trick, 下面给点启发性的例子 (如果不感兴趣, 你可以跳过这段): template<class T = void> struct less { template<class T> bool operator()(const T& a, const T& b) const { return a < b; } }; template<..., class _Pred = less<void>> void sort(..., const _Pred& compare = {}) { ... } 说简单点, 就是 less 给了一个默认模板实例化类型 void; 而真正进行比较的 operator() 又是一个模板. 调用 sort 时, 不用考虑第三个参数 (函数对像) 具体是什么类型, 反正 operator() 在比较时会自行实例化. 可以参考以下使用案例: // Under C++ 14 (or later) standard. #include <algorithm> #include <functional> double arr_double[4] = { 1,9.1,0.9,-3.1 }; std::sort(arr_double, arr_double + 4); // std::less<void> std::sort(arr_double, arr_double + 4, std::less()); // std::less<void> std::sort(arr_double, arr_double + 4, std::less<double>()); // std::less<double> int arr_int[4] = { 1,3,4,0 }; std::sort(arr_double, arr_double + 4, std::less()); // std::less<int> std::sort() 排其他类型实例 如果看懂了前面的内容, 想必你也能够猜出来怎么实现这个问题了. 注意, std::less 之类的谓语类型说到底就是结构体, 和我们上面实现的 good_less 没啥区别. 所以如果我们还是要排序上文提到的 MyStruct 数组: // Omit the definition of class <MyStruct>. // Omit the definition of class <good_less>. // Omit the definition of class <good_greater>. #include <algorithm> MyStruct arr_MyStruct[4] = { {1,4},{3,1},{9,-1},{12,0} }; // Ascending order: std::sort(arr_MyStruct, arr_MyStruct + 4, good_less<MyStruct>()); // Descending order: std::sort(arr_MyStruct, arr_MyStruct + 4, good_greater<MyStruct>()); 统一指针和迭代器 作为一个 STL 使用者, 难免会遇到指针与迭代器不统一的问题. 例如以下例子: // Use pointer: int arr_int[] = ...; std::sort(arr_int, ...); // Use iterator: std::vector<int> arr_vector = ...; std::sort(arr_vector.begin(), ...); 解决方式之一是统一泛化指针类型和迭代器类型, 这里把它们都当作类 _RandIt . 我们还是以最开始的 insertionSort 为例, 给出示范代码. 需要注意的是, 通过迭代器和指针获取元素类型 (用来定义 key )时, decltype 会保留解引用 (dereference) 后留下的引用 & (也就是说 decltype(arr_int[0]) 得到的类型不是 int 而是 int& ); 因此需要调用 std::remove_reference 来删除类型中的引用. using index = long long; template<class _RandIt, class _Pr = std::less<void>> void insertionSort(_RandIt seq, index firstIndex, index lastIndex, const _Pr& comp = {}) { for (index j = firstIndex + 1; j <= lastIndex; ++j) { typename std::remove_reference<decltype(*seq)>::type key = seq[j]; index i = j - 1; while (i >= firstIndex && comp(key, seq[i])) { seq[i + 1] = seq[i]; --i; } seq[i + 1] = key; } } 再给个归并排序的代码吧! 就说到这里 (计组完全没学, 寄). using index = long long; template<class _RandIt, class _Pr> void merge(_RandIt seq, index subAFirst, index subALast, index subBLast, auto MAX, auto MIN, const _Pr& comp) { auto END = comp(1, 2) ? MAX : MIN; size_t sizeSubA = subALast - subAFirst + 2; size_t sizeSubB = subBLast - subALast + 1; auto subA = new typename std::remove_reference<decltype(*seq)>::type[sizeSubA]; std::copy(seq + subAFirst, seq + subALast + 1, subA); subA[sizeSubA - 1] = END; auto subB = new typename std::remove_reference<decltype(*seq)>::type[sizeSubB]; std::copy(seq + subALast + 1, seq + subBLast + 1, subB); subB[sizeSubB - 1] = END; // Merge two subsequences to origin {seq[subAFirst : subBLast]}: for (index k = subAFirst, i = 0, j = 0; k <= subBLast; ++k) { if (i >= sizeSubA || j >= sizeSubB) return; // Merge: if (comp(subA[i], subB[j])) { seq[k] = subA[i]; ++i; } else { seq[k] = subB[j]; ++j; } } delete[] subA; delete[] subB; } template<class _RandIt, class _Pr = std::less<void>> void mergeSort(_RandIt seq, index firstIndex, index lastIndex, auto MAX, auto MIN, const _Pr& comp = {}) { if (firstIndex >= lastIndex) return; index mid = (firstIndex + lastIndex) / 2; mergeSort(seq, firstIndex, mid, MAX, MIN, comp); mergeSort(seq, mid + 1, lastIndex, MAX, MIN, comp); merge(seq, firstIndex, mid, lastIndex, MAX, MIN, comp); }
2024-01-19
118
0
0
网络聚合
2024-01-19
spring事务里面开启线程插入,报错了是否会回滚?
1.前言 一道非常有意思的面试题目。大概是这样子的,如果在一个事务中,开启线程进行插入更新等操作,如果报错了,事务是否会进行回滚 2.代码 示例1 @RequestMapping("/test/publish/submit") public String testPublish1() { log.info("start..."); transactionTemplate.execute(new TransactionCallback<String>() { @Override public String doInTransaction(TransactionStatus status) { TElement element = new TElement(); element.setfElementId(10L); element.setfElementName("111"); mapper.insertSelective(element); element = new TElement(); element.setfElementId(10L); element.setfElementName("222"); mapper.insertSelective(element); return "OK"; } }); log.info("end..."); return "ok"; } 示例2 @RequestMapping("/test/publish/submit2") public String testPublish2() { log.info("start..."); transactionTemplate.execute(new TransactionCallback<String>() { @Override public String doInTransaction(TransactionStatus status) { es.submit(() -> { TElement element = new TElement(); element.setfElementId(10L); element.setfElementName("111"); mapper.insertSelective(element); }); es.submit(() -> { TElement element = new TElement(); element.setfElementId(10L); element.setfElementName("222"); mapper.insertSelective(element); }); return "OK"; } }); log.info("end..."); return "ok"; } 3.结论 示例1 element.setfElementId(10L); 为主键。SQL在第一次插入id=10的时候是没有问题的,在第二次插入id=10的时候,由于主键冲突了,导致报错,然后整个事务都会进行回滚,这是没有问题的。是spring的事务帮助我们来进行回滚等操作的。我们可以看到如下代码,他是对整个result = action.doInTransaction(status);进行了try catch。如果抛异常,就会回滚 @Override @Nullable public <T> T execute(TransactionCallback<T> action) throws TransactionException { Assert.state(this.transactionManager != null, "No PlatformTransactionManager set"); if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); } else { TransactionStatus status = this.transactionManager.getTransaction(this); T result; try { result = action.doInTransaction(status); } catch (RuntimeException | Error ex) { // Transactional code threw application exception -> rollback rollbackOnException(status, ex); throw ex; } catch (Throwable ex) { // Transactional code threw unexpected exception -> rollback rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } this.transactionManager.commit(status); return result; } } 示例2 示例2首先是transactionTemplate.execute是一个主main线程。然后在第一个子线程插入了一个数据,第二个子线程也插入了一个数据。那么现在就是有三个线程,一个是main线程,一个是A线程,一个是B线程。 main线程正常执行不报错,A线程正常插入不报错,B线程由于主键冲突报错。 我们可以通过上面action.doInTransaction(status);看出来,他对这块代码进行了try catch。也就是主线程进行了try catch。那么也就是只要主线程没有报错,这个事务就不会被捕获,也就不会回滚了。无论你A,B还是CDEFG子线程出问题了,只要不影响main线程,那事务就不会回滚呢? 因此我们可以得出一个结论,在示例2中,A线程会插入成功,B线程插入失败,事务不会回滚,最终插入成功。这个其实与我们平常的想法所违背了。 因此如果想要主线程抛出异常,得让主线程感知到子线程异常了,主动地去throw异常。比如我们可以设置一个flag,子线程报错了 flag=true。主线程检测到flag为true,就主动抛出一个exception 4.最后 这道面试题非常有意思,起初以为会回滚,没想到不会回滚。查看代码得知,原来是catch住的是主线程,并不是子线程。同样注解式事务类似。因此如果想要事务生效,尽量避免在事务中使用多线程来进行插入更新等操作
2024-01-19
132
0
0
网络聚合
63
64
65
66
67