获得徽章 7
在 Go(Golang)中,**数据类型**分为两大类:
- **值类型(Value Types)**
- **引用类型(Reference Types)**
理解这两类的区别非常重要,因为它直接影响到赋值、参数传递和内存管理的行为。
---
## 📘 一、引用类型(Reference Types)
在 Go 中,**以下四类是引用类型**:
| 类型 | 说明 |
|------|------|
| `slice`(切片) | 对底层数组的引用。多个切片可以共享同一个底层数组。 |
| `map`(映射) | 类似哈希表,内部实际是一个引用结构。复制 map 变量时,只会复制引用。 |
| `channel`(通道) | goroutine 之间通信的引用类型。复制 channel 变量不会复制底层通道。 |
| `function`(函数) | 函数类型的变量实际上是指向函数体的引用。 |
---
### 1. **slice**
切片由三部分组成:
- 指针(指向底层数组)
- 长度(len)
- 容量(cap)
```go
a := []int{1, 2, 3}
b := a // b 引用了同一个底层数组
b[0] = 99
fmt.Println(a[0]) // 输出 99,说明两者共享底层数据
```
---
### 2. **map**
`map` 是一个引用类型。它内部使用哈希表实现,但变量本身只是对底层哈希结构的引用。
```go
m1 := map[string]int{"x": 1}
m2 := m1
m2["x"] = 100
fmt.Println(m1["x"]) // 输出 100
```
---
### 3. **channel**
`channel` 用于 goroutine 间通信。复制通道变量不会创建新的通道。
```go
ch1 := make(chan int)
ch2 := ch1
go func() {
ch2 <- 10
}()
fmt.Println(<-ch1) // 输出 10,说明 ch1 和 ch2 引用了相同通道
```
- **值类型(Value Types)**
- **引用类型(Reference Types)**
理解这两类的区别非常重要,因为它直接影响到赋值、参数传递和内存管理的行为。
---
## 📘 一、引用类型(Reference Types)
在 Go 中,**以下四类是引用类型**:
| 类型 | 说明 |
|------|------|
| `slice`(切片) | 对底层数组的引用。多个切片可以共享同一个底层数组。 |
| `map`(映射) | 类似哈希表,内部实际是一个引用结构。复制 map 变量时,只会复制引用。 |
| `channel`(通道) | goroutine 之间通信的引用类型。复制 channel 变量不会复制底层通道。 |
| `function`(函数) | 函数类型的变量实际上是指向函数体的引用。 |
---
### 1. **slice**
切片由三部分组成:
- 指针(指向底层数组)
- 长度(len)
- 容量(cap)
```go
a := []int{1, 2, 3}
b := a // b 引用了同一个底层数组
b[0] = 99
fmt.Println(a[0]) // 输出 99,说明两者共享底层数据
```
---
### 2. **map**
`map` 是一个引用类型。它内部使用哈希表实现,但变量本身只是对底层哈希结构的引用。
```go
m1 := map[string]int{"x": 1}
m2 := m1
m2["x"] = 100
fmt.Println(m1["x"]) // 输出 100
```
---
### 3. **channel**
`channel` 用于 goroutine 间通信。复制通道变量不会创建新的通道。
```go
ch1 := make(chan int)
ch2 := ch1
go func() {
ch2 <- 10
}()
fmt.Println(<-ch1) // 输出 10,说明 ch1 和 ch2 引用了相同通道
```
展开
评论
2
### Operator 工作原理
```
Reconciliation Loop(调谐循环):
1. 观察当前状态
↓
2. 读取期望状态(从CRD)
↓
3. 比较差异
↓
4. 执行操作使当前状态 → 期望状态
↓
5. 回到步骤1(不断循环)
```
Reconciliation Loop(调谐循环):
1. 观察当前状态
↓
2. 读取期望状态(从CRD)
↓
3. 比较差异
↓
4. 执行操作使当前状态 → 期望状态
↓
5. 回到步骤1(不断循环)
展开
1
1
// LeetCode 704: 二分查找
func search(nums []int, target int) int {
return BinarySearch(nums, target)
}
// LeetCode 35: 搜索插入位置
func searchInsert(nums []int, target int) int {
left, right := 0, len(nums)-1
for left <= right {
mid := left + (right-left)/2
if nums[mid] == target {
return mid
} else if nums[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return left // 返回插入位置
}
// LeetCode 34: 在排序数组中查找元素的第一个和最后一个位置
func searchRange(nums []int, target int) []int {
first := FindFirst(nums, target)
if first == -1 {
return []int{-1, -1}
}
last := FindLast(nums, target)
return []int{first, last}
}
```
## 八、记忆口诀
```
二分查找三要素:
1. 左闭右闭定边界 (left, right := 0, len-1)
2. 循环条件带等号 (left <= right)
3. 中点防溢出公式 (left + (right-left)/2)
更新规则记心间:
- 找到目标直接返
- 小于目标左加一 (left = mid + 1)
- 大于目标右减一 (right = mid - 1)
func search(nums []int, target int) int {
return BinarySearch(nums, target)
}
// LeetCode 35: 搜索插入位置
func searchInsert(nums []int, target int) int {
left, right := 0, len(nums)-1
for left <= right {
mid := left + (right-left)/2
if nums[mid] == target {
return mid
} else if nums[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return left // 返回插入位置
}
// LeetCode 34: 在排序数组中查找元素的第一个和最后一个位置
func searchRange(nums []int, target int) []int {
first := FindFirst(nums, target)
if first == -1 {
return []int{-1, -1}
}
last := FindLast(nums, target)
return []int{first, last}
}
```
## 八、记忆口诀
```
二分查找三要素:
1. 左闭右闭定边界 (left, right := 0, len-1)
2. 循环条件带等号 (left <= right)
3. 中点防溢出公式 (left + (right-left)/2)
更新规则记心间:
- 找到目标直接返
- 小于目标左加一 (left = mid + 1)
- 大于目标右减一 (right = mid - 1)
展开
2
1
在Linux/Unix系统中,**僵尸进程**会占用资源,而孤儿进程不会造成额外的资源占用问题。
## 僵尸进程(Zombie Process)
**会占用系统资源**,但占用量很小:
- 进程已经终止,释放了内存、文件描述符等大部分资源
- 但进程表(PCB)中的条目仍然保留,包含退出状态信息
- 占用一个进程ID(PID)
- 如果僵尸进程大量累积,会耗尽系统的进程表空间,导致无法创建新进程
**产生原因**:子进程终止后,父进程没有调用wait()或waitpid()来回收子进程的退出状态。
## 孤儿进程(Orphan Process)
**不会造成资源占用问题**:
- 孤儿进程是正常运行的进程,只是父进程提前终止了
- 系统会自动将孤儿进程过继给init进程(PID为1)或systemd
- init/systemd会负责回收这些进程,当它们终止时会自动调用wait()
- 孤儿进程作为正常进程运行,使用正常的系统资源
**产生原因**:父进程先于子进程终止。
## 总结
僵尸进程是需要关注的问题,特别是当父进程编写不当,长期不回收子进程时。而孤儿进程则是被系统妥善处理的,不会造成资源泄漏。
## 僵尸进程(Zombie Process)
**会占用系统资源**,但占用量很小:
- 进程已经终止,释放了内存、文件描述符等大部分资源
- 但进程表(PCB)中的条目仍然保留,包含退出状态信息
- 占用一个进程ID(PID)
- 如果僵尸进程大量累积,会耗尽系统的进程表空间,导致无法创建新进程
**产生原因**:子进程终止后,父进程没有调用wait()或waitpid()来回收子进程的退出状态。
## 孤儿进程(Orphan Process)
**不会造成资源占用问题**:
- 孤儿进程是正常运行的进程,只是父进程提前终止了
- 系统会自动将孤儿进程过继给init进程(PID为1)或systemd
- init/systemd会负责回收这些进程,当它们终止时会自动调用wait()
- 孤儿进程作为正常进程运行,使用正常的系统资源
**产生原因**:父进程先于子进程终止。
## 总结
僵尸进程是需要关注的问题,特别是当父进程编写不当,长期不回收子进程时。而孤儿进程则是被系统妥善处理的,不会造成资源泄漏。
展开
评论
点赞
两阶段提交流程:
完整流程:
1. 执行器调用InnoDB开始事务
2. InnoDB修改数据,写入undo log(记录旧值)
3. InnoDB更新内存(Buffer Pool)
4. InnoDB写入redo log,状态为 prepare
5. 执行器生成binlog,写入磁盘
6. 执行器调用InnoDB提交事务
7. InnoDB将redo log状态改为 commit
完整流程:
1. 执行器调用InnoDB开始事务
2. InnoDB修改数据,写入undo log(记录旧值)
3. InnoDB更新内存(Buffer Pool)
4. InnoDB写入redo log,状态为 prepare
5. 执行器生成binlog,写入磁盘
6. 执行器调用InnoDB提交事务
7. InnoDB将redo log状态改为 commit
展开
评论
点赞
MVCC 负责解决 普通查询(SELECT) 时的幻读问题(基于版本快照,看到的行数据一致)。
间隙锁(Gap Lock)+ 临键锁(Next-Key Lock) 起作用于 更新(UPDATE / DELETE / INSERT) 时,
锁定「记录之间的间隙」从而防止新的行被插入,消除了幻读。
间隙锁(Gap Lock)+ 临键锁(Next-Key Lock) 起作用于 更新(UPDATE / DELETE / INSERT) 时,
锁定「记录之间的间隙」从而防止新的行被插入,消除了幻读。
1
点赞
> TCP 建立连接要经过三次握手:
> 1️⃣ **第一次**:客户端发送 `SYN` 报文,请求建立连接;
> 2️⃣ **第二次**:服务器收到后回复 `SYN+ACK`,表示同意并确认客户端请求;
> 3️⃣ **第三次**:客户端收到后再回 `ACK` 确认,连接正式建立。
📘 **目的:**
让双方都确认彼此的 **发送和接收能力正常**,并防止历史连接的干扰。
展开
评论
点赞
ClickHouse 是一个列式数据库管理系统,以其高性能和高效的查询能力而闻名。其快速性能的原因主要包括以下几个方面:
### 1. 列式存储
- **数据布局**:ClickHouse 将数据按列而不是按行存储,这样可以有效地压缩数据。对于大多数分析查询而言,通常只会读取需要的几列,从而减少了I/O操作。
### 2. 压缩技术
- **高效压缩算法**:ClickHouse 使用各种压缩算法(如 LZ77、LZ4 等)对列数据进行压缩,能够显著减少存储空间,从而提速数据读取。
### 3. 向量化执行
- **批量处理**:ClickHouse 采用向量化执行引擎,允许一次性处理多个行(或列)。这种方式充分利用了现代 CPU 的 SIMD(单指令多数据)特性,从而加速数据处理。
### 4. 并行处理
- **分布式架构**:ClickHouse 支持分布式查询,可以在多台服务器上并行处理请求,利用网络和硬件资源达到更高的性能。
### 5. 数据分区与索引
- **数据分区**:支持基于时间或其他键值对数据进行分区,以减少扫描的数据量。
- **索引**:ClickHouse 提供了几种索引类型(如稀疏索引、主键索引)来加速查询。
### 6. 高效的缓存机制
- **内存缓存**:ClickHouse 使用内存缓存以加快常用数据的访问速度。查询优化器也会利用缓存的结果来加速重复查询。
### 7. 灵活的 SQL 查询优化
- **查询优化器**:智能的查询优化功能,能够根据数据特点优化执行计划,从而提高查询速度。
### 8. 支持高吞吐量
- **批量插入**:支持高效的批量数据插入,能够快速处理大规模数据集。
### 9. 硬件利用
- **利用现代硬件**:ClickHouse 设计上考虑了对硬件的充分利用,包括多核 CPU 和高速度的 SSD 存储。
### 总结
ClickHouse 之所以表现出色,是因为其独特的列式存储方式、高效的压缩和查询技术、分布式架构以及灵活的优化机制。这些特性使得它在处理大规模数据时,能够实现快速查询和高吞吐量。
### 1. 列式存储
- **数据布局**:ClickHouse 将数据按列而不是按行存储,这样可以有效地压缩数据。对于大多数分析查询而言,通常只会读取需要的几列,从而减少了I/O操作。
### 2. 压缩技术
- **高效压缩算法**:ClickHouse 使用各种压缩算法(如 LZ77、LZ4 等)对列数据进行压缩,能够显著减少存储空间,从而提速数据读取。
### 3. 向量化执行
- **批量处理**:ClickHouse 采用向量化执行引擎,允许一次性处理多个行(或列)。这种方式充分利用了现代 CPU 的 SIMD(单指令多数据)特性,从而加速数据处理。
### 4. 并行处理
- **分布式架构**:ClickHouse 支持分布式查询,可以在多台服务器上并行处理请求,利用网络和硬件资源达到更高的性能。
### 5. 数据分区与索引
- **数据分区**:支持基于时间或其他键值对数据进行分区,以减少扫描的数据量。
- **索引**:ClickHouse 提供了几种索引类型(如稀疏索引、主键索引)来加速查询。
### 6. 高效的缓存机制
- **内存缓存**:ClickHouse 使用内存缓存以加快常用数据的访问速度。查询优化器也会利用缓存的结果来加速重复查询。
### 7. 灵活的 SQL 查询优化
- **查询优化器**:智能的查询优化功能,能够根据数据特点优化执行计划,从而提高查询速度。
### 8. 支持高吞吐量
- **批量插入**:支持高效的批量数据插入,能够快速处理大规模数据集。
### 9. 硬件利用
- **利用现代硬件**:ClickHouse 设计上考虑了对硬件的充分利用,包括多核 CPU 和高速度的 SSD 存储。
### 总结
ClickHouse 之所以表现出色,是因为其独特的列式存储方式、高效的压缩和查询技术、分布式架构以及灵活的优化机制。这些特性使得它在处理大规模数据时,能够实现快速查询和高吞吐量。
展开
评论
点赞
倒排索引(Inverted Index)是一种用于快速查找的索引数据结构,广泛应用于信息检索系统(如搜索引擎)和数据库中。其主要作用是将文档中的词汇(或关键词)和包含这些词汇的文档进行关联,从而实现快速的全文检索。
### 倒排索引的基本结构
1. **词汇表(Vocabulary)**:所有文档中出现的唯一词汇的列表。
2. **倒排列表(Posting List)**:每个词汇对应的文档列表,通常还包含词频、位置等信息。
### 倒排索引的作用
1. **快速检索**:通过查找特定词汇的倒排列表,可以迅速找到包含该词汇的所有文档。
2. **提高搜索效率**:相比于传统的顺序查找,倒排索引显著减少了查询时间,尤其是在大量数据中。
3. **支持复杂查询**:可以更方便地处理布尔查询(如 AND、OR、NOT)以及短语查询和范围查询。
4. **信息提取**:帮助快速获取文档的相关信息,例如文档频率、词的位置等。
### 应用场景
- **搜索引擎**:如 Google、Bing 通过倒排索引来实现快速搜索。
- **文档管理系统**:快速查找和检索电子文档。
- **自然语言处理**:帮助分析文本中的关键词和主题。
总的来说,倒排索引是实现高效数据检索的重要技术基础。
### 倒排索引的基本结构
1. **词汇表(Vocabulary)**:所有文档中出现的唯一词汇的列表。
2. **倒排列表(Posting List)**:每个词汇对应的文档列表,通常还包含词频、位置等信息。
### 倒排索引的作用
1. **快速检索**:通过查找特定词汇的倒排列表,可以迅速找到包含该词汇的所有文档。
2. **提高搜索效率**:相比于传统的顺序查找,倒排索引显著减少了查询时间,尤其是在大量数据中。
3. **支持复杂查询**:可以更方便地处理布尔查询(如 AND、OR、NOT)以及短语查询和范围查询。
4. **信息提取**:帮助快速获取文档的相关信息,例如文档频率、词的位置等。
### 应用场景
- **搜索引擎**:如 Google、Bing 通过倒排索引来实现快速搜索。
- **文档管理系统**:快速查找和检索电子文档。
- **自然语言处理**:帮助分析文本中的关键词和主题。
总的来说,倒排索引是实现高效数据检索的重要技术基础。
展开
评论
点赞
LRU 核心数据结构
要同时做到:
O(1) 访问元素
O(1) 插入/删除元素
LRU 一般用 两个数据结构配合实现:
数据结构 作用 时间复杂度
哈希表(Hash Map) 通过 key 快速定位到对应节点 O(1)
双向链表(Doubly Linked List) 维持元素访问顺序(最近使用靠前) O(1)
要同时做到:
O(1) 访问元素
O(1) 插入/删除元素
数据结构 作用 时间复杂度
哈希表(Hash Map) 通过 key 快速定位到对应节点 O(1)
双向链表(Doubly Linked List) 维持元素访问顺序(最近使用靠前) O(1)
展开
评论
点赞