超专业解析!10分钟带你搞懂Linux中直接I/O原理
我们先看一张图:
这张图大体上描述了 Linux 系统上,应用程序对磁盘上的文件进行读写时,从上到下经历了哪些事情。
这篇文章就以这张图为基础,介绍 Linux 在 I/O 上做了哪些事情。
文件系统
什么是文件系统
文件系统,本身是对存储设备上的文件,进行组织管理的机制。组织方式不同,就会形成不同的文件系统。比如常见的 Ext4、XFS、ZFS 以及网络文件系统 NFS 等等。
但是不同类型的文件系统标准和接口可能各有差异,我们在做应用开发的时候却很少关心系统调用以下的具体实现,大部分时候都是直接系统调用 open, read, write, close 来实现应用程序的功能,不会再去关注我们具体用了什么文件系统(UFS、XFS、Ext4、ZFS),磁盘是什么接口(IDE、SCSI,SAS,SATA 等),磁盘是什么存储介质(HDD、SSD)
应用开发者之所以这么爽,各种复杂细节都不用管直接调接口,是因为内核为我们做了大量的有技术含量的脏活累活。开始的那张图看到 Linux 在各种不同的文件系统之上,虚拟了一个 VFS,目的就是统一各种不同文件系统的标准和接口,让开发者可以使用相同的系统调用来使用不同的文件系统。
文件系统如何工作(VFS)
Linux 系统下的文件
在 Linux 中一切皆文件。不仅普通的文件和目录,就连块设备、套接字、管道等,也都要通过统一的文件系统来管理。
用 ls -l 命令看最前面的字符可以看到这个文件是什么类型brw-r--r-- 1 root root 1, 2 4月 25 11:03 bnod // 块设备文件
crw-r--r-- 1 root root 1, 2 4月 25 11:04 cnod // 符号设备文件
drwxr-xr-x 2 wrn3552 wrn3552 6 4月 25 11:01 dir // 目录
-rw-r--r-- 1 wrn3552 wrn3552 0 4月 25 11:01 file // 普通文件
prw-r--r-- 1 root root 0 4月 25 11:04 pipeline // 有名管道
srwxr-xr-x 1 root root 0 4月 25 11:06 socket.sock // socket文件
lrwxrwxrwx 1 root root 4 4月 25 11:04 softlink -> file // 软连接
-rw-r--r-- 2 wrn3552 wrn3552 0 4月 25 11:07 hardlink // 硬链接(本质也是普通文件)
Linux 文件系统设计了两个数据结构来管理这些不同种类的文件:
- inode(index node):索引节点
- dentry(directory entry):目录项
inode 和 dentry
inode
inode 是用来记录文件的 metadata,所谓 metadata 在 Wikipedia 上的描述是 data of data,其实指的就是文件的各种属性,比如 inode 编号、文件大小、访问权限、修改日期、数据的位置等。
wrn3552@novadev:~/playground$ stat file文件:file大小:0 块:0 IO 块:4096 普通空文件
设备:fe21h/65057d Inode:32828 硬链接:2
权限:(0644/-rw-r--r--) Uid:( 3041/ wrn3552) Gid:( 3041/ wrn3552)
最近访问:2021-04-25 11:07:59.603745534 +0800
最近更改:2021-04-25 11:07:59.603745534 +0800
最近改动:2021-04-25 11:08:04.739848692 +0800
创建时间:-
inode 和文件一一对应,它跟文件内容一样,都会被持久化存储到磁盘中。所以,inode 同样占用磁盘空间,只不过相对于文件来说它大小固定且大小不算大。
dentry
dentry 用来记录文件的名字、inode 指针以及与其他 dentry 的关联关系。
wrn3552@novadev:~/playground$ tree
.
├── dir
│ └── file_in_dir
├── file
└── hardlink
- 文件的名字:像 dir、file、hardlink、file_in_dir 这些名字是记录在 dentry 里的
- inode 指针:就是指向这个文件的 inode
- 与其他 dentry 的关联关系:其实就是每个文件的层级关系,哪个文件在哪个文件下面,构成了文件系统的目录结构
不同于 inode,dentry 是由内核维护的一个内存数据结构,所以通常也被叫做 dentry cache。
相关视频推荐
3个linux内核的秘密,让你彻底搞懂文件系统
剖析Linux内核虚拟文件系统(VFS)架构
免费学习地址:C/C++Linux服务器开发/后台架构师
需要C/C++ Linux服务器架构师学习资料加qun812855908获取(资料包括C/C++,Linux,golang技术,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg等),免费分享
文件是如何存储在磁盘上的
这里有张图解释了文件是如何存储在磁盘上的,首先,磁盘再进行文件系统格式化的时候,会分出来 3 个区:
- Superblock
- inode blocks
- data blocks
(其实还有 boot block,可能会包含一些 bootstrap 代码,在机器启动的时候被读到,这里忽略)其中 inode blocks 放的都是每个文件的 inode,data blocks 里放的是每个文件的内容数据。这里关注一下 superblock,它包含了整个文件系统的 metadata,具体有:
- inode/data block 总量、使用量、剩余量
- 文件系统的格式,属主等等各种属性
superblock 对于文件系统来说非常重要,如果 superblock 损坏了,文件系统就挂载不了了,相应的文件也没办法读写。既然 superblock 这么重要,那肯定不能只有一份,坏了就没了,它在系统中是有很多副本的,在 superblock 损坏的时候,可以使用 fsck(File System Check and repair)来恢复。回到上面的那张图,可以很清晰地看到文件的各种属性和文件的数据是如何存储在磁盘上的:
- dentry 里包含了文件的名字、目录结构、inode 指针
- inode 指针指向文件特定的 inode(存在 inode blocks 里)
- 每个 inode 又指向 data blocks 里具体的 logical block,这里的 logical block 存的就是文件具体的数据
这里解释一下什么是 logical block:
- 对于不同存储介质的磁盘,都有最小的读写单元
- /sys/block/sda/queue/physical_block_size
- HDD 叫做 sector(扇区),SSD 叫做 page(页面)
- 对于 hdd 来说,每个 sector 大小 512Bytes
- 对于 SSD 来说每个 page 大小不等(和 cell 类型有关),经典的大小是 4KB
- 但是 Linux 觉得按照存储介质的最小读写单元来进行读写可能会有效率问题,所以支持在文件系统格式化的时候指定 block size 的大小,一般是把几个 physical_block 拼起来就成了一个 logical block
- /sys/block/sda/queue/logical_block_size
- 理论上应该是 logical_block_size >= physical_block_size,但是有时候我们会看到 physical_block_size = 4K,logical_block_size = 512B 情况,其实这是因为磁盘上做了一层 512B 的仿真(emulation)(详情可参考 512e 和 4Kn)
ZFS
这里简单介绍一个广泛应用的文件系统 ZFS,一些数据库应用也会用到 ZFS,先看一张 zfs 的层级结构图:
这是一张从底向上的图:
- 将若干物理设备 disk 组成一个虚拟设备 vdev(同时,disk 也是一种 vdev)
- 再将若干个虚拟设备 vdev 加到一个 zpool 里
- 在 zpool 的基础上创建 zfs 并挂载(zvol 可以先不看,我们没有用到)
ZFS 的一些操作
创建 zpool
root@:~ # zpool create tank raidz /dev/ada1 /dev/ada2 /dev/ada3 raidz /dev/ada4 /dev/ada5 /dev/ada6
root@:~ # zpool list tank
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
tank 11G 824K 11.0G - - 0% 0% 1.00x ONLINE -
root@:~ # zpool status tankpool: tankstate: ONLINEscan: none requested
config:NAME STATE READ WRITE CKSUMtank ONLINE 0 0 0raidz1-0 ONLINE 0 0 0ada1 ONLINE 0 0 0ada2 ONLINE 0 0 0ada3 ONLINE 0 0 0raidz1-1 ONLINE 0 0 0ada4 ONLINE 0 0 0ada5 ONLINE 0 0 0ada6 ONLINE 0 0 0
- 创建了一个名为 tank 的 zpool
- 这里的 raidz 同 RAID5
除了 raidz 还支持其他方案:
创建 zfs
root@:~ # zfs create -o mountpoint=/mnt/srev tank/srev
root@:~ # df -h tank/srev
Filesystem Size Used Avail Capacity Mounted on
tank/srev 7.1G 117K 7.1G 0% /mnt/srev
- 创建了一个 zfs,挂载到了 /mnt/srev
- 这里没有指定 zfs 的 quota,创建的 zfs 大小即 zpool 大小
对 zfs 设置 quota
root@:~ # zfs set quota=1G tank/srev
root@:~ # df -h tank/srev
Filesystem Size Used Avail Capacity Mounted on
tank/srev 1.0G 118K 1.0G 0% /mnt/srev
ZFS 特性
Pool 存储
上面的层级图和操作步骤可以看到 zfs 是基于 zpool 创建的,zpool 可以动态扩容意味着存储空间也可以动态扩容,而且可以创建多个文件系统,文件系统共享完整的 zpool 空间无需预分配。
事务文件系统
zfs 的写操作是事务的,意味着要么就没写,要么就写成功了,不会像其他文件系统那样,应用打开了文件,写入还没保存的时候断电,导致文件为空。zfs 保证写操作事务采用的是 copy on write 的方式:
- 当 block B 有修改变成 B1 的时候,普通的文件系统会直接在 block B 原地进行修改变成 B1
- zfs 则会再另一个地方写 B1,然后再在后面安全的时候对原来的 B 进行回收
- 这样结果就不会出现 B 被打开而写失败的情况,大不了就是 B1 没写成功
这个特性让 zfs 在断电后不需要执行 fsck 来检查磁盘中是否存在写操作失败需要恢复的情况,大大提升了应用的可用性。
ARC 缓存
ZFS 中的 ARC(Adjustable Replacement Cache) 读缓存淘汰算法,是基于 IBM 的 ARP(Adaptive Replacement Cache) 演化而来。在一些文件系统中实现的标准 LRU 算法其实是有缺陷的:比如复制大文件之类的线性大量 I/O 操作,导致缓存失效率猛增(大量文件只读一次,放到内存不会被再读,坐等淘汰)。
另外,缓存可以根据时间来进行优化(LRU,最近最多使用),也可以根据频率进行优化(LFU,最近最常使用),这两种方法各有优劣,但是没办法适应所有场景。
ARC 的设计就是尝试在 LRU 和 LFU 之间找到一个平衡,根据当前的 I/O workload 来调整用 LRU 多一点还是 LFU 多一点。
ARC 定义了 4 个链表:
- LRU list:最近最多使用的页面,存具体数据
- LFU list:最近最常使用的页面,存具体数据
- Ghost list for LRU:最近从 LRU 表淘汰下来的页面信息,不存具体数据,只存页面信息
- Ghost list for LFU:最近从 LFU 表淘汰下来的页面信息,不存具体数据,只存页面信息
ARC 工作流程大致如下:
- LRU list 和 LFU list 填充和淘汰过程和标准算法一样
- 当一个页面从 LRU list 淘汰下来时,这个页面的信息会放到 LRU ghost 表中
- 如果这个页面一直没被再次引用到,那么这个页面的信息最终也会在 LRU ghost 表中被淘汰掉
- 如果这个页面在 LRU ghost 表中未被淘汰的时候,被再一次访问了,这时候会引起一次幽灵(phantom)命中
- phantom 命中的时候,事实上还是要把数据从磁盘第一次放缓存
- 但是这时候系统知道刚刚被 LRU 表淘汰的页面又被访问到了,说明 LRU list 太小了,这时它会把 LRU list 长度加一,LFU 长度减一
- 对于 LFU 的过程也与上述过程类似
ZFS 参考资料
关于 ZFS 详细介绍可以参考:
- 这篇文章
磁盘类型
磁盘根据不同的分类方式,有各种不一样的类型。
磁盘的存储介质
根据磁盘的存储介质可以分两类(大家都很熟悉):
- HDD(机械硬盘)
- SSD(固态硬盘)
磁盘的接口
根据磁盘接口分类:
- IDE (Integrated Drive Electronics)
- SCSI (Small Computer System Interface)
- SAS (Serial Attached SCSI)
- SATA (Serial ATA)
- ...
不同的接口,往往分配不同的设备名称。比如, IDE 设备会分配一个 hd 前缀的设备名,SCSI 和 SATA 设备会分配一个 sd 前缀的设备名。如果是多块同类型的磁盘,就会按照 a、b、c 等的字母顺序来编号。
Linux 对磁盘的管理
其实在 Linux 中,磁盘实际上是作为一个块设备来管理的,也就是以块为单位读写数据,并且支持随机读写。每个块设备都会被赋予两个设备号,分别是主、次设备号。主设备号用在驱动程序中,用来区分设备类型;而次设备号则是用来给多个同类设备编号。
g18-"299" on ~# ls -l /dev/sda*
brw-rw---- 1 root disk 8, 0 Apr 25 15:53 /dev/sda
brw-rw---- 1 root disk 8, 1 Apr 25 15:53 /dev/sda1
brw-rw---- 1 root disk 8, 10 Apr 25 15:53 /dev/sda10
brw-rw---- 1 root disk 8, 2 Apr 25 15:53 /dev/sda2
brw-rw---- 1 root disk 8, 5 Apr 25 15:53 /dev/sda5
brw-rw---- 1 root disk 8, 6 Apr 25 15:53 /dev/sda6
brw-rw---- 1 root disk 8, 7 Apr 25 15:53 /dev/sda7
brw-rw---- 1 root disk 8, 8 Apr 25 15:53 /dev/sda8
brw-rw---- 1 root disk 8, 9 Apr 25 15:53 /dev/sda9
- 这些 sda 磁盘主设备号都是 8,表示它是一个 sd 类型的块设备
- 次设备号 0-10 表示这些不同 sd 块设备的编号
Generic Block Layer
和 VFS 类似,为了对上层屏蔽不同块设备的差异,内核在文件系统和块设备之前抽象了一个 Generic Block Layer(通用块层),有时候一些人也会把下面的 I/O 调度层并到通用块层里表述。
这两层主要做两件事:
- 跟 VFS 的功能类似。向上,为文件系统和应用程序,提供访问块设备的标准接口;向下,把各种异构的磁盘设备抽象为统一的块设备,并提供统一框架来管理这些设备的驱动程序
- 对 I/O 请求进行调度,通过重新排序、合并等方式,提高磁盘读写效率
下图是一个完整的 I/O 栈全景图:
可以看到中间的 Block Layer 其实就是 Generic Block Layer,在图中可以看到 Block Layer 的 I/O 调度分为两类,分别表示单队列和多队列的调度:
- I/O scheduler
- blkmq
I/O 调度
老版本的内核里只支持单队列的 I/O scheduler,在 3.16 版本的内核开始支持多队列 blkmq,这里介绍几种经典的 I/O 调度策略。
单队列 I/O scheduler:
- NOOP:事实上是个 FIFO 的队列,只做基本的请求合并
- CFQ:Completely Fair Queueing,完全公平调度器,给每个进程维护一个 I/O 调度队列,按照时间片来均匀分布每个进程 I/O 请求,
- DeadLine:为读和写请求创建不同的 I/O 队列,确保达到 deadline 的请求被优先处理
多队列 blkmq:
- bfq:Budget Fair Queueing,也是公平调度器,不过不是按时间片来分配,而是按请求的扇区数量(带宽)
- kyber:维护两个队列(同步/读、异步/写),同时严格限制发到这两个队列的请求数以保证相应时间
- mq-deadline:多队列版本的 deadline
- 具体各种 I/O 调度策略可以参考 IOSchedulers
- 关于 blkmq 可以参考 Linux Multi-Queue Block IO Queueing Mechanism (blk-mq) Details
- 多队列调度可以参考 Block layer introduction part 2: the request layer
性能指标
一般来说 I/O 性能指标有这几个:
- 使用率:ioutil,指的是磁盘处理 I/O 的时间百分比,ioutil 只看有没有 I/O 请求,不看 I/O 请求的大小。ioutil 越高表示一直都有 I/O 请求,不代表磁盘无法响应新的 I/O 请求
- IOPS:每秒的 I/O 请求数
- 吞吐量/带宽:每秒的 I/O 请求大小,通常是 MB/s 或者 GB/s 为单位
- 响应时间:I/O 请求发出到收到响应的时间
- 饱和度:指的是磁盘处理 I/O 的繁忙程度。这个指标比较玄学,没有直接的数据可以表示,一般是根据平均队列请求长度或者响应时间跟基准测试的结果进行对比来估算
(在做基准测试时,还会分顺序/随机、读/写进行排列组合分别去测 IOPS 和带宽)
上面的指标除了饱和度外,其他都可以在监控系统中看到。Linux 也提供了一些命令来输出不同维度的 I/O 状态:
- iostat -d -x:看各个设备的 I/O 状态,数据来源 /proc/diskstats
- pidstat -d:看近处的 I/O
- iotop:类似 top,按 I/O 大小对进程排序
相关文章:

超专业解析!10分钟带你搞懂Linux中直接I/O原理
我们先看一张图: 这张图大体上描述了 Linux 系统上,应用程序对磁盘上的文件进行读写时,从上到下经历了哪些事情。 这篇文章就以这张图为基础,介绍 Linux 在 I/O 上做了哪些事情。 文件系统 什么是文件系统 文件系统࿰…...

【C++】面试101,用两个栈实现队列,包含min函数的栈,有效括号序列,滑动窗口的最大值,最小的K个数,倒置字符串,排序子序列,跳跃,数字三角形,蓝肽子序列
目录 1. 用两个栈实现队列 2.包含min函数的栈 3.有效括号序列 4.滑动窗口的最大值 5.最小的K个数 6.倒置字符串 7.排序子序列 8.数字三角形(蓝桥杯,学习一个大佬的博客....) 9.跳跃(蓝桥杯) 10.蓝肽子序列 1. 用…...

WPF 认识WPF
什么是WPF?WPF是Windows Presentation Foundation(Windows展示基础)简称,顾名思义是专门编写表示层的技术。WPF绚丽界面如下:GUI发展及WPF历史?Windows系统平台上从事图形用户界面GUI(Graphic User Interface)已经经历了多次换代,…...

【建议收藏】PHP单例模式详解以及实际运用
PHP单例模式详解以及实际运用 什么是单例模式? 首先我们百度百科他怎么说? 单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如&a…...

【十二天学java】day04-流程控制语句
第一章 流程控制语句 在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。所以,我们必须清楚每条语句的执行流程。而且,很多时候要通过控制语句的执行顺序来实现我们想要的功能。 1.1 流程控制语句分类 顺序结构 判断…...

Pandas 与 PySpark 强强联手,功能与速度齐飞
Pandas做数据处理可以说是yyds!而它的缺点也是非常明显,Pandas 只能单机处理,它不能随数据量线性伸缩。例如,如果 pandas 试图读取的数据集大于一台机器的可用内存,则会因内存不足而失败。 另外 pandas 在处理大型数据…...

【Zabbix实战之部署篇】docker部署Zabbix+grafana监控平台
【Zabbix实战之部署篇】docker部署Zabbix+grafana监控平台 一、Zabbix介绍1.Zabbix简介2.Zabbix的优点3.Zabbix各组件介绍4.Zabbix架构图二、grafana介绍1.grafana简介2.grafana特点三、实践环境规划四、检查本地docker环境1.检查操作系统版本2.检查docker版本3.检查docker服务…...

acm省赛:高桥和低桥(三种做法:区间计数、树状数组、线段树)
题目描述 有个脑筋急转弯是这样的:有距离很近的一高一低两座桥,两次洪水之后高桥被淹了两次,低桥却只被淹了一次,为什么?答案是:因为低桥太低了,第一次洪水退去之后水位依然在低桥之上ÿ…...

stm32-定时器详解
0. 概述 本文针对STM32F1系列,主要讲解了其中的8个定时器的原理和功能 1. 定时器分类 STM32F1 系列中,除了互联型的产品,共有 8 个定时器,分为基本定时器,通用定时器和高级定时器基本定时器 TIM6 和 TIM7 是一个 16 位…...

《硬件架构的艺术》读书笔记:Chapter 1 亚稳态的世界
Chapter 1 亚稳态的世界 一、简介 同步系统中,数据和时钟有固定的因果关系(在同一时钟域(Clock Domains))中,只要数据和时钟满足建立时间和保持时间的要求,不会产生亚稳态(meastable) 静态时序分析(STA) 就是基于同步电路设计模型而出现的&am…...

开箱即用的密码框组件
写了一个小玩具,分享一下 - 组件功能: 初次进入页面时,密码隐藏显示,且无法查看真实密码 当修改密码时,触发键盘,输入框则会直接清空 此时输入密码,可以设置密码的隐藏或显示: …...

ChatGPT能否取代程序员?
目录ChatGPT能否取代程序员?ChatGPT和程序员的工作内容和工作方式ChatGPT和程序员的共同点程序员的优势程序员的实力ChatGPT和程序员的关系结论惊喜ChatGPT能否取代程序员? ChatGPT是一种非常普遍的人工智能(AI)系统,…...

案例分享 | 金融微服务场景下如何提升运维可观测性
云原生环境下金融业务的微服务化改造以及分布式架构的部署,使得业务与开发部门的关联更为紧密,传统运维监控已满足不了业务运营需求,亟需建设具备可观测性的运维体系。所以这次我们以某金融客户的实践案例为例,跟大家说一说在金…...

CentOS8提高篇3:Centos8安装播放器(mplayer vlc)
1. 准备工作(需要配置epel, rpmfusion源); 配置epel源 下载epel dnf install epel-release 配置rpmfusion源 下载rpmforge dnf install rpmfusion-free-release-8.noarch.rpm 2. 安装mplayer和vlc 直接dnf安装 # dnf install mplayer # dnf install v…...

MySQL-存储过程
什么是存储过程我们前面所学习的MySQL语句都是针对一个表或几个表的单条 SQL 语句,但是在数据库的实际操作中,并非所有操作都那么简单,经常会有一个完整的操作需要多条SQL语句处理多个表才能完成。例如,为了确认学生能否毕业&…...

经典七大比较排序算法 · 下 + 附计数和基数排序
经典七大比较排序算法 下 附计数和基数排序1 插入排序1.1 算法思想1.2 代码实现1.3 插入排序特性2 希尔排序2.1 算法思想2.2 代码实现2.3 希尔排序特性3 七大比较排序特性总结4 计数排序4.1 算法思想4.2 代码实现4.3 计数排序特性5 基数排序5.1 算法思想5.2 代码实现1 插入排…...

HTTPS协议,看这篇就够了
不安全的HTTP 近些年来,越来越多的网站使用 HTTPS 协议进行数据传输,原因在于 HTTPS 相较于 HTTP 能够提供更加安全的服务。 很多浏览器对于使用 HTTP 协议的网站会加上『警告』的标志表示数据传输不安全,而对于使用 HTTPS 协议的网站会加上…...

C语言学习之路--结构体篇
目录一、前言二、结构体的声明1、结构的基础知识2、结构的声明3、结构体成员的类型4、结构体变量的定义和初始化三、结构体成员的访问四、结构体传参一、前言 本人是一名小白,这一篇是记录我C语言学习中的结构体的所学所得,仅为简单的认识下C语言中的各…...

【LINUX】初识文件系统
文章目录一、前言二、回顾C语言文件操作三、初识系统调用openreadwriteclose四、文件系统初识五、结语一、前言 二、回顾C语言文件操作 int main() {FILE* fp fopen("log.txt", "w");if (fp NULL){perror("fopen");}int cnt 0;fputs("…...

金三银四Java面试题及答案整理(2023最新版) 持续更新
作为一名优秀的程序员,技术面试是不可避免的一个环节,一般技术面试官都会通过自己的方式去考察程序员的技术功底与基础理论知识。 如果你参加过一些大厂面试,肯定会遇到一些这样的问题: 1、看你项目都用的框架,熟悉 …...

7个角度,用 ChatGPT 玩转机器学习
大家好,我是机器学习科普创作者章北海mlpy,探索更高效的学习方法是我一直等追求。现在的初学者太幸福了,可以利用ChatGPT来帮助你学习机器学习的各个方面。 比如【个人首测】百度文心一言 VS GPT-4这篇文章中,我就用文心一言、GP…...

关于多层板,你了解多少?
01 前言 大家好,我是张巧龙。好久没写原创了,记得之前刚接触PCB时,还在用腐蚀单层板,类似这种。 慢慢随着电子产品功能越来越多,产品越来越薄,对PCB设计要求越来越高了,复杂程度也随之增加。因此…...

使用sqlalchemy-gbasedbt连接GBase 8s数据库
测试环境: 操作系统:CentOS 7.9 64-bit数据库版本:GBase8sV8.8_AEE_3.0.0_1,对应的CSDK版本为3.0.0_1 1,确认安装python3 确认已经安装python3和python3-devel [rootlocalhost test]# python3 -V Python 3.6.8如果…...

前端如何丢掉你的饭碗?
对于后端而言,我们常有“删库跑路”的说法,这说明后端的操作对于信息系统而言通常影响很大,可以轻易使信息系统宕机、崩溃,直接导致项目失败。所以,不要去逼后端程序员! 作为前端程序员,我们似…...

栈、队列、优先级队列的模拟实现
优先级队列的模拟实现栈stack的模拟实现push()pop()top()size()empty()swap()stack总代码队列queue的模拟实现push()pop()front()back()empty()size()swap()queue总代码优先级队列(堆)push()pop()top()empty()size()swap()priority_queue总代码deque的了解栈 在CSTL中栈并不属…...

JMM内存模型
JMM内存模型JMM内存模型定义三大特性原子性可见性有序性volatile语义JMM规则操作系统实现术语缓存一致性要求缓存一致性机制写传播事务串行化重排序as-if-serial 语义(像是有序的)happens-before 原则happens-before 原则的八大子原则内存屏障总结finalf…...

Linux- 系统随你玩之--玩出花活的命令浏览器-双生姐妹花
文章目录1、背景2、命令浏览器-双生姐妹花2.1、姐妹花简介2.2 、验名正身2.3、常用功能选项3、常用实操3.1、发送请求获取文件3.1.1、抓取页面内容到一个文件中3.1.2、多个文件下载3.1.3、下载ftp文件3.1.4、断点续传3.1.5、上传文件3.1.6、内容输出3.2 、利用curl测试接口3.3 …...

【深度学习】基于Hough变化的答题卡识别(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。⛳座右铭&#…...

Linux - 进程控制(创建和终止)
1.进程创建fork函数初识 在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。返回值:子进程返回0,父进程返回子进程id,出错返回-1getpid()获取子进程id,…...

依赖注入~
依赖注入之setter注入: 依赖注入是IOC具体的一种实现方式, 这是针对资源获取的方式角度来说的,之前我们是被动接受,现在IOC具体的实现叫做依赖注入,从代码的角度来说,原来创建对象的时候需要new࿰…...