diff --git a/技术/Go/GC.md b/技术/Go/GC.md new file mode 100644 index 0000000..381690e --- /dev/null +++ b/技术/Go/GC.md @@ -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混合写屏障机制的全场景分析 + diff --git a/技术/Go/Go实现BitMap.md b/技术/Go/Go实现BitMap.md new file mode 100644 index 0000000..6589e44 --- /dev/null +++ b/技术/Go/Go实现BitMap.md @@ -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<= 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 +} + +~~~ \ No newline at end of file diff --git a/技术/Go/算法相关.md b/技术/Go/算法相关.md index 917bb45..c259d15 100644 --- a/技术/Go/算法相关.md +++ b/技术/Go/算法相关.md @@ -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 { diff --git a/技术/MySQL/基础.md b/技术/MySQL/基础.md index b85c6c6..427b9c1 100644 --- a/技术/MySQL/基础.md +++ b/技术/MySQL/基础.md @@ -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 + ## 执行一条语句操作日志的完整过程 @@ -118,4 +158,71 @@ Read View 有四个重要的字段: - 如果记录的 trx_id **在** m_ids 列表中,表示生成该版本记录的活跃事务依然活跃着(还没提交事务),所以该版本的记录对当前事务**不可见**。 - 如果记录的 trx_id **不在** m_ids列表中,表示生成该版本记录的活跃事务已经被提交,所以该版本的记录对当前事务**可见**。 -**这种通过「版本链」来控制并发事务访问同一个记录时的行为就叫 MVCC(多版本并发控制)** \ No newline at end of file +**这种通过「版本链」来控制并发事务访问同一个记录时的行为就叫 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` 不受时区影响。 diff --git a/技术/其他.md b/技术/其他.md new file mode 100644 index 0000000..c999a16 --- /dev/null +++ b/技术/其他.md @@ -0,0 +1,2 @@ +## 说一下Docker的原理 +Docker是基于LXC架构之上的,它通过使用Docker引擎来管理和操作容器。Docker引擎包含了一个Docker守护进程和一组API,可以用来创建、启动、停止、删除和管理Docker容器。LXC是一种轻量级的虚拟化技术,它依赖于Linux内核提供的cgroups和命名空间(Namespaces)功能来实现容器隔离。 \ No newline at end of file diff --git a/技术/项目设计/分布式与系统一致性.md b/技术/项目设计/分布式与系统一致性.md index dd491e1..711dbf7 100644 --- a/技术/项目设计/分布式与系统一致性.md +++ b/技术/项目设计/分布式与系统一致性.md @@ -6,9 +6,9 @@ 1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标: -> * Consistency -> * Availability -> * Partition tolerance +> * Consistency 一致性 +> * Availability 可用性 +> * Partition tolerance 分区容错性 它们的第一个字母分别是 `C`、`A`、`P`。Eric Brewer 说,这三个指标不可能同时做到。这个结论就叫做 `CAP` 定理。