2025-03-25-01

This commit is contained in:
kaku 2025-03-25 17:57:51 +08:00
parent 6536fc0460
commit ffb1da1215
6 changed files with 360 additions and 9 deletions

10
技术/Go/GC.md Normal file
View File

@ -0,0 +1,10 @@
## Golang在GC的演进过程中也经历了很多次变革Go V1.3之前的[标记-清除](https://zhida.zhihu.com/search?content_id=238158259&content_type=Article&match_order=1&q=%E6%A0%87%E8%AE%B0-%E6%B8%85%E9%99%A4&zd_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGlkYV9zZXJ2ZXIiLCJleHAiOjE3NDI3OTg1ODcsInEiOiLmoIforrAt5riF6ZmkIiwiemhpZGFfc291cmNlIjoiZW50aXR5IiwiY29udGVudF9pZCI6MjM4MTU4MjU5LCJjb250ZW50X3R5cGUiOiJBcnRpY2xlIiwibWF0Y2hfb3JkZXIiOjEsInpkX3Rva2VuIjpudWxsfQ.L519Jm1YZEEQ1wuzajxX2OOBhbTH7DbPZHy8nn6Obns&zhida_source=entity)(mark and sweep)算法。Go V1.3之前的标记-清扫(mark and sweep)的缺点。
大家可以重点关注以下版本的变化:
- Go V1.5的[三色并发标记法](https://zhida.zhihu.com/search?content_id=238158259&content_type=Article&match_order=1&q=%E4%B8%89%E8%89%B2%E5%B9%B6%E5%8F%91%E6%A0%87%E8%AE%B0%E6%B3%95&zd_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGlkYV9zZXJ2ZXIiLCJleHAiOjE3NDI3OTg1ODcsInEiOiLkuInoibLlubblj5HmoIforrDms5UiLCJ6aGlkYV9zb3VyY2UiOiJlbnRpdHkiLCJjb250ZW50X2lkIjoyMzgxNTgyNTksImNvbnRlbnRfdHlwZSI6IkFydGljbGUiLCJtYXRjaF9vcmRlciI6MSwiemRfdG9rZW4iOm51bGx9.uWrIm2OB1_oK7lijlD4chkrpuqwtlbJ3MTtVKVst36c&zhida_source=entity)
- Go V1.5的三色标记为什么需要STW
- Go V1.5的三色标记为什么需要[屏障机制](https://zhida.zhihu.com/search?content_id=238158259&content_type=Article&match_order=1&q=%E5%B1%8F%E9%9A%9C%E6%9C%BA%E5%88%B6&zd_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGlkYV9zZXJ2ZXIiLCJleHAiOjE3NDI3OTg1ODcsInEiOiLlsY_pmpzmnLrliLYiLCJ6aGlkYV9zb3VyY2UiOiJlbnRpdHkiLCJjb250ZW50X2lkIjoyMzgxNTgyNTksImNvbnRlbnRfdHlwZSI6IkFydGljbGUiLCJtYXRjaF9vcmRlciI6MSwiemRfdG9rZW4iOm51bGx9.z_KFIcdz9agqmRw6oF9lyMLd_pCuwW8t9F3iG5Rf264&zhida_source=entity)(“强-弱” 三色不变式、插入屏障、删除屏障 )
- Go V1.8[混合写屏障](https://zhida.zhihu.com/search?content_id=238158259&content_type=Article&match_order=1&q=%E6%B7%B7%E5%90%88%E5%86%99%E5%B1%8F%E9%9A%9C&zd_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ6aGlkYV9zZXJ2ZXIiLCJleHAiOjE3NDI3OTg1ODcsInEiOiLmt7flkIjlhpnlsY_pmpwiLCJ6aGlkYV9zb3VyY2UiOiJlbnRpdHkiLCJjb250ZW50X2lkIjoyMzgxNTgyNTksImNvbnRlbnRfdHlwZSI6IkFydGljbGUiLCJtYXRjaF9vcmRlciI6MSwiemRfdG9rZW4iOm51bGx9.bbCbV48D0n6tpBTp3s-Ia-MV3I-tnPAEhS6Bg1JVFog&zhida_source=entity)机制
- Go V1.8混合写屏障机制的全场景分析

183
技术/Go/Go实现BitMap.md Normal file
View File

@ -0,0 +1,183 @@
在 Go 语言中,`uint64` 是一种无符号整数类型,占用 64 位bit。每一位可以存储一个布尔值0 或 1。以下是 `bit``uint64` 之间的对应关系及操作的详细解释:
---
### 1. **`uint64` 的结构**
- 一个 `uint64` 类型的变量由 64 个二进制位组成,例如:
```
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
```
每一位从右到左编号为 0 到 63最低位是第 0 位,最高位是第 63 位)。
---
### 2. **如何定位某个位**
假设我们要操作第 `pos` 位(从 0 开始计数),可以通过以下步骤确定其在 `uint64` 中的位置:
#### (1) **计算所在 `uint64` 的索引**
- 如果位图使用多个 `uint64` 来存储数据,则需要先确定目标位所在的 `uint64` 索引。
- 公式为:
```go
index = pos / 64
```
- `pos / 64` 表示将位的位置除以 64得到它属于哪个 `uint64`
#### (2) **计算具体位偏移量**
- 在确定了目标 `uint64` 后,需要进一步确定该位在当前 `uint64` 中的具体位置。
- 公式为:
```go
offset = pos % 64
```
- `pos % 64` 表示取余运算,得到目标位在当前 `uint64` 中的偏移量(范围为 0 到 63
---
### 3. **位操作的实现**
Go 语言提供了位运算符来操作单个位。以下是常见的位操作及其作用:
#### (1) **设置某一位为 1**
- 使用按位或运算符 `|` 和左移运算符 `<<`
```go
b.bits[pos/64] |= 1 << uint(pos%64)
```
- `1 << uint(pos%64)`:将数字 `1` 左移 `offset` 位,生成一个只有目标位为 1 的掩码。
- `|=`:将掩码与当前 `uint64` 值进行按位或运算,确保目标位被设置为 1。
#### (2) **清除某一位为 0**
- 使用按位与运算符 `&` 和按位取反运算符 `^`
```go
b.bits[pos/64] &^= 1 << uint(pos%64)
```
- `1 << uint(pos%64)`:生成一个只有目标位为 1 的掩码。
- `&^=`:将掩码取反后与当前 `uint64` 值进行按位与运算,确保目标位被清除为 0。
#### (3) **检查某一位是否为 1**
- 使用按位与运算符 `&`
```go
return b.bits[pos/64]&(1<<uint(pos%64)) != 0
```
- `1 << uint(pos%64)`:生成一个只有目标位为 1 的掩码。
- `&`:将掩码与当前 `uint64` 值进行按位与运算,结果非零表示目标位为 1否则为 0。
---
### 4. **举例说明**
假设我们有一个 `uint64`,初始值为 `0`
```
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
```
#### (1) 设置第 10 位为 1
- 计算索引和偏移量:
- `index = 10 / 64 = 0`
- `offset = 10 % 64 = 10`
- 执行操作:
```go
bits[0] |= 1 << 10
```
结果:
```
00000000 00000000 00000000 00000000 00000000 00000000 00000100 00000000
```
#### (2) 清除第 10 位为 0
- 执行操作:
```go
bits[0] &^= 1 << 10
```
结果:
```
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
```
#### (3) 检查第 10 位是否为 1
- 执行操作:
```go
result := bits[0]&(1<<10) != 0
```
- 如果第 10 位为 1`result``true`
- 如果第 10 位为 0`result``false`
---
### 5. **总结**
- `uint64` 是一个 64 位的存储单元,每一位可以独立存储一个布尔值。
- 通过 `pos / 64` 确定目标位所在的 `uint64`,通过 `pos % 64` 确定目标位在当前 `uint64` 中的具体位置。
- 使用位运算符(如 `|``&``^``<<`)可以高效地操作单个位。
## 6.代码实现
~~~ go
package main
import (
"fmt"
)
// Bitmap 结构体表示位图
type Bitmap struct {
bits []uint64 // 使用一个 uint64 切片存储位图数据,每个元素存储 64 位
size int // 位图的总大小(位数)
}
// NewBitmap 创建一个新的位图size为位图的大小
func NewBitmap(size int) *Bitmap {
if size < 0 {
size = 0
}
return &Bitmap{
bits: make([]uint64, (size+63)/64), // 根据位图大小计算需要的 uint64 元素数量
size: size, // 记录位图的总大小
}
}
// SetBit 设置指定位置的位为1
func (b *Bitmap) SetBit(pos int) {
if pos < 0 || pos >= b.size { // 检查位置是否越界
return
}
idx := pos / 64
offset := pos % 64
// 使用 uint64(1) 避免可能的整数溢出问题
b.bits[idx] |= uint64(1) << offset
}
// ClearBit 清除指定位置的位为0
func (b *Bitmap) ClearBit(pos int) {
if pos < 0 || pos >= b.size { // 检查位置是否越界
return
}
idx := pos / 64
offset := pos % 64
// 使用 uint64(1) 避免可能的整数溢出问题
b.bits[idx] &^= uint64(1) << offset
}
// GetBit 获取指定位置的位
func (b *Bitmap) GetBit(pos int) bool {
if pos < 0 || pos >= b.size { // 检查位置是否越界
return false
}
idx := pos / 64
offset := pos % 64
// 使用 uint64(1) 避免可能的整数溢出问题
return (b.bits[idx] & (uint64(1) << offset)) != 0
}
func main() {
// 创建一个大小为 100 的位图
bitmap := NewBitmap(100)
// 设置第 10 位为 1
bitmap.SetBit(10)
// 检查第 10 位是否为 1并打印结果输出 true
fmt.Println(bitmap.GetBit(10)) // 输出: true
// 清除第 10 位为 0
bitmap.ClearBit(10)
// 再次检查第 10 位是否为 1并打印结果输出 false
fmt.Println(bitmap.GetBit(10)) // 输出: false
}
~~~

View File

@ -3,6 +3,55 @@
2^x = 1 << x
x/2 x >> 1
~~~
## 递增的三元子序列
给你一个整数数组 `nums` ,判断这个数组中是否存在长度为 `3` 的递增子序列。
如果存在这样的三元组下标 `(i, j, k)` 且满足 `i < j < k` ,使得 `nums[i] < nums[j] < nums[k]` ,返回 `true` ;否则,返回 `false` 。
~~~ go
func increasingTriplet(nums []int) bool {
n := len(nums)
if n < 3 {
return false
}
first, sencond := nums[0], math.MaxInt32
for i := 1;i < n;i++ {
num := nums[i]
if num > sencond {
return true
} else if num > first {
sencond = num
} else {
first = num
}
}
return false
}
~~~
赋初始值的时候已经满足second > first了现在找第三个数third
(1) 如果third比second大那就是找到了直接返回true
(2) 如果third比second小但是比first大那就把second指向third然后继续遍历找third
(3) 如果third比first还小那就把first指向third然后继续遍历找third这样的话first会跑到second的后边但是不要紧因为在second的前边老first还是满足的
## 字符串的最大公因子
~~~ go
func gcdOfStrings(str1 string, str2 string) string {
if str1+str2 != str2+str1 {
return ""
}
return str1[:gcd(len(str1), len(str2))]
}
// 欧几里得法求最大公因数
func gcd(a, b int) int {
if b == 0 {
return a
}
return gcd(b, a%b)
}
~~~
## 快乐数
~~~ go
func isHappy(n int) bool {
@ -424,7 +473,7 @@ func addStrings(num1 string, num2 string) string {
for i, j := len(num1)-1, len(num2)-1; j >= 0 || i >= 0; {
num := add
if i >= 0 {
num += int(num1[i] - '0')
num += int(num1[i] - '0') //转Int
i--
}
if j >= 0 {

View File

@ -8,6 +8,40 @@
| **扩展性** | 通常采用垂直扩展(增加硬件性能),扩展性有限 。 | 支持水平扩展(增加节点),适合大规模分布式系统,扩展性更强 。 |
| **查询语言** | 使用SQL结构化查询语言通用性强且易于理解 。 | 通常使用特定API或查询语言灵活性更高但学习成本较大 。 |
| **适用场景** | 适合需要复杂查询、事务处理和强一致性的场景如银行系统、ERP等 。 | 适合大数据、高并发、实时性要求高的场景,如社交网络、物联网等 。 |
## 数据库设计三大范式
数据库设计的三大范式是关系型数据库设计中用于减少数据冗余、提高数据一致性和可维护性的基本原则。以下是三大范式的具体定义和要求:
### 1. **第一范式1NF**
第一范式要求确保表中的每列都具有原子性,即字段值不可再分解。换句话说,每一列的值必须是单一的、不可分割的基本数据项,不能包含多个值或复杂结构。
- **目标**:消除重复组或多值字段。
- **示例**:在一个学生信息表中,如果“联系方式”列存储了多个电话号码,则违反了第一范式。应该将其拆分为单独的行或表以满足原子性。
---
### 2. **第二范式2NF**
第二范式建立在第一范式的基础上,要求表中的每一列都必须完全依赖于主键,而不能仅仅依赖于主键的一部分(即消除部分依赖)。这意味着当表的主键是由多个列组成的复合主键时,非主键列必须与整个主键相关联。
- **目标**:消除部分依赖。
- **示例**假设有一个订单明细表主键由“订单ID”和“商品ID”组成。如果表中还存在“客户姓名”这样的列它只依赖于“订单ID”而不依赖于“商品ID”这就违反了第二范式。应将“客户姓名”移到另一个表中。
---
### 3. **第三范式3NF**
第三范式建立在第二范式的基础上,要求表中的每一列都必须直接依赖于主键,而不能通过其他非主键列间接依赖于主键(即消除传递依赖)。
- **目标**:消除间接依赖。
- **示例**在一个员工信息表中如果存在“部门ID”和“部门名称”两列“部门名称”依赖于“部门ID”而不是直接依赖于主键如“员工ID”这就违反了第三范式。应将“部门名称”移到一个独立的部门表中。
---
### 总结
- **第一范式1NF**:确保每列保持原子性,字段值不可再分。
- **第二范式2NF**:确保每列完全依赖于主键,消除部分依赖。
- **第三范式3NF**:确保每列直接依赖于主键,消除传递依赖。
遵循这三大范式可以有效地减少数据冗余,提高数据库的规范性和一致性。不过,在实际应用中,有时为了性能或其他需求,可能会对范式进行适当的反规范化处理。
## 2. 为什么我们需要索引
@ -46,17 +80,23 @@
## Mysql有哪些日志简单概括有什么用
MySQL 中有多种日志,每种日志的作用各不相同,以下是它们的简单概括:
1. **Binlog二进制日志**
1. **Binlog二进制日志** 保证
- **作用**记录所有对数据库的修改操作DDL 和 DML 语句),但不包括查询语句(如 SELECT、SHOW。主要用于数据恢复、主从复制和审计 。
- **特点**:以二进制格式存储,支持 STATEMENT、ROW 和 MIXED 三种模式记录 。
2. **Redo Log重做日志**
- **作用**:保证事务的持久性。记录的是数据页的物理修改,用于在 MySQL 崩溃后恢复未写入磁盘的数据(即“崩溃恢复”)。
- **作用**:保证事务的**持久性**。记录的是数据页的物理修改,用于在 MySQL 崩溃后恢复未写入磁盘的数据(即“崩溃恢复”)。
- **特点**:循环写入,固定大小,保存未刷入磁盘的脏页日志 。
3. **Undo Log回滚日志**
- **作用**:保证事务的原子性。记录的是事务执行前的数据状态,用于回滚操作或实现 MVCC多版本并发控制
- **特点**:与 Redo Log 配合使用,确保事务的一致性和隔离性。
- **作用**:保证事务的**原子性**。记录的是事务执行前的数据状态,用于回滚操作或实现 MVCC多版本并发控制
- **特点**:与 Redo Log 配合使用,确保事务的**一致性**和**隔离性**。
原子性--> Undo Log
一致性--> 其他几项同时保证
持久性--> Redo Log
隔离性--> MVCC LBCC
## 执行一条语句操作日志的完整过程
@ -119,3 +159,70 @@ Read View 有四个重要的字段:
- 如果记录的 trx_id **不在** m_ids列表中表示生成该版本记录的活跃事务已经被提交所以该版本的记录对当前事务**可见**。
**这种通过「版本链」来控制并发事务访问同一个记录时的行为就叫 MVCC多版本并发控制**
## Mysql数据类型
以下是MySQL中常用的数据类型分类及其说明的表格按照类别进行了整理方便查阅
---
### **数值类型**
| 数据类型 | 存储大小 | 范围 (有符号) | 范围 (无符号) | 描述 |
|----------------|---------------|-----------------------------------------|---------------------------------|----------------------------------------|
| `TINYINT` | 1 字节 | -128 到 127 | 0 到 255 | 非常小的整数 |
| `SMALLINT` | 2 字节 | -32,768 到 32,767 | 0 到 65,535 | 小整数 |
| `MEDIUMINT` | 3 字节 | -8,388,608 到 8,388,607 | 0 到 16,777,215 | 中等大小的整数 |
| `INT``INTEGER` | 4 字节 | -2,147,483,648 到 2,147,483,647 | 0 到 4,294,967,295 | 标准整数 |
| `BIGINT` | 8 字节 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 | 0 到 18,446,744,073,709,551,615 | 大整数 |
| `FLOAT` | 4 字节 | -3.402823466E+38 到 -1.175494351E-38 和 1.175494351E-38 到 3.402823466E+38 | 0 和 1.175494351E-38 到 3.402823466E+38 | 单精度浮点数 |
| `DOUBLE` | 8 字节 | -1.7976931348623157E+308 到 -2.2250738585072014E-308 和 2.2250738585072014E-308 到 1.7976931348623157E+308 | 0 和 2.2250738585072014E-308 到 1.7976931348623157E+308 | 双精度浮点数 |
| `DECIMAL(M,D)`| 可变 | 依赖于 M 和 D 的值 | 依赖于 M 和 D 的值 | 精确的小数值M 是总位数D 是小数位数 |
### **日期和时间类型**
| 数据类型 | 存储大小 | 范围 | 格式 | 描述 |
|----------------|---------------|-----------------------------------------|--------------------|----------------------------------------|
| `DATE` | 3 字节 | '1000-01-01' 到 '9999-12-31' | YYYY-MM-DD | 仅存储日期 |
| `TIME` | 3 字节 | '-838:59:59' 到 '838:59:59' | HH:MM:SS | 仅存储时间 |
| `DATETIME` | 8 字节 | '1000-01-01 00:00:00' 到 '9999-12-31 23:59:59' | YYYY-MM-DD HH:MM:SS | 日期和时间的组合 |
| `TIMESTAMP` | 4 字节 | '1970-01-01 00:00:01' UTC 到 '2038-01-19 03:14:07' UTC | YYYY-MM-DD HH:MM:SS | 时间戳,通常用于记录时间戳 |
| `YEAR` | 1 字节 | '1901' 到 '2155' | YYYY | 仅存储年份 |
### **字符串类型**
| 数据类型 | 最大长度 | 存储需求 | 描述 |
|----------------|----------------|---------------------------------------|----------------------------------------|
| `CHAR(M)` | 0-255 字符 | M × 字符集字节数 | 固定长度字符串,不足补空格 |
| `VARCHAR(M)` | 0-65,535 字节 | 实际长度 + 1 或 2 字节 | 可变长度字符串 |
| `TEXT` | 0-65,535 字节 | L + 2 字节 | 长文本数据 |
| `TINYTEXT` | 0-255 字节 | L + 1 字节 | 小型文本数据 |
| `MEDIUMTEXT` | 0-16,777,215 字节 | L + 3 字节 | 中型文本数据 |
| `LONGTEXT` | 0-4,294,967,295 字节 | L + 4 字节 | 超长文本数据 |
| `BLOB` | 0-65,535 字节 | L + 2 字节 | 二进制大对象 |
| `TINYBLOB` | 0-255 字节 | L + 1 字节 | 小型二进制对象 |
| `MEDIUMBLOB` | 0-16,777,215 字节 | L + 3 字节 | 中型二进制对象 |
| `LONGBLOB` | 0-4,294,967,295 字节 | L + 4 字节 | 超长二进制对象 |
| `ENUM` | 1 或 2 字节 | 最多 65,535 个值 | 枚举类型,只能从预定义列表中选择一个值 |
| `SET` | 1、2、3、4 或 8 字节 | 最多 64 个成员 | 集合类型,可以选择多个值 |
### **空间类型**
| 数据类型 | 描述 |
|----------------|----------------------------------------|
| `GEOMETRY` | 几何类型的基类 |
| `POINT` | 表示一个点 |
| `LINESTRING` | 表示一条线 |
| `POLYGON` | 表示一个多边形 |
| `MULTIPOINT` | 表示多个点 |
| `MULTILINESTRING` | 表示多条线 |
| `MULTIPOLYGON`| 表示多个多边形 |
| `GEOMETRYCOLLECTION` | 表示几何对象的集合 |
### **JSON 类型**
| 数据类型 | 描述 |
|----------------|----------------------------------------|
| `JSON` | 用于存储 JSON 文档 |
---
### **注意事项**
1. **字符集影响**:对于字符串类型(如 `CHAR``VARCHAR`),实际存储大小会受到字符集的影响。例如,使用 UTF-8 编码时,每个字符可能占用 1 到 4 个字节。
2. **存储效率**:选择合适的数据类型可以显著提高存储效率和查询性能。例如,如果只需要存储小范围的整数,优先选择 `TINYINT` 而非 `INT`
3. **时间戳与 DATETIME**`TIMESTAMP` 类型受时区影响,而 `DATETIME` 不受时区影响。

2
技术/其他.md Normal file
View File

@ -0,0 +1,2 @@
## 说一下Docker的原理
Docker是基于LXC架构之上的它通过使用Docker引擎来管理和操作容器。Docker引擎包含了一个Docker守护进程和一组API可以用来创建、启动、停止、删除和管理Docker容器。LXC是一种轻量级的虚拟化技术它依赖于Linux内核提供的cgroups和命名空间Namespaces功能来实现容器隔离。

View File

@ -6,9 +6,9 @@
1998年加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标:
> * Consistency
> * Availability
> * Partition tolerance
> * Consistency 一致性
> * Availability 可用性
> * Partition tolerance 分区容错性
它们的第一个字母分别是 `C``A``P`。Eric Brewer 说,这三个指标不可能同时做到。这个结论就叫做 `CAP` 定理。