docs(note): reorganize notes structure and migrate content
- Move Windows and 算法 notes from 随手记 to 资源 directory - Migrate Golang map pitfalls and dot import notes to Golang/使用注意 - Delete omos配置 note - Add Typora custom theme reference link
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
## 快速复制文件路径
|
||||
|
||||
### Shift + 右键菜单(通用)
|
||||
|
||||
1. 在文件资源管理器中,**按住 `Shift` 键不放**
|
||||
2. 右键点击目标文件
|
||||
3. 选择 **「复制为路径(A)」**
|
||||
|
||||
### 功能区按钮
|
||||
|
||||
1. 选中文件
|
||||
2. 点击资源管理器顶部的 **「主页」** 选项卡
|
||||
3. 点击 **「复制路径」** 按钮(剪贴板图标)
|
||||
|
||||
### 拖拽到终端
|
||||
|
||||
- 直接把文件**拖入** PowerShell 或 CMD 窗口,会自动粘贴完整路径。
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
## 轮询算法
|
||||
|
||||
### 平滑加权轮询
|
||||
|
||||
#### 原理
|
||||
|
||||
每台服务器维护一个 `当前权重`(currentWeight),每次选择 `currentWeight` 最大的服务器,选中后将其 `currentWeight` 减去总权重,然后**所有服务器都加上自己的固定权重**。如此循环,高权重节点被选中的频率更高,但不会连续出现。
|
||||
|
||||
#### 实际应用
|
||||
|
||||
- **Nginx** 的 `upstream` 默认负载均衡算法
|
||||
- **LVS**(Linux Virtual Server)
|
||||
- 几乎所有需要「按比例分配且平滑」的场景
|
||||
|
||||
#### 轮询示例
|
||||
|
||||
```go
|
||||
type server struct {
|
||||
name string
|
||||
weight int
|
||||
curWeight int
|
||||
}
|
||||
|
||||
func NextServer(servers []*server) *server {
|
||||
var totalWeight int
|
||||
// 1.先给所有服务器加上各自的固定权重
|
||||
for i := range servers {
|
||||
servers[i].curWeight += servers[i].weight
|
||||
totalWeight += servers[i].weight
|
||||
}
|
||||
// 2.再找出 curWeight 最大的服务器
|
||||
maxIdx := 0
|
||||
for i := 1; i < len(servers); i++ {
|
||||
if servers[i].curWeight > servers[maxIdx].curWeight {
|
||||
maxIdx = i
|
||||
}
|
||||
}
|
||||
// 3.选中的服务器减去总权重
|
||||
servers[maxIdx].curWeight -= totalWeight
|
||||
return servers[maxIdx]
|
||||
}
|
||||
```
|
||||
|
||||
| 轮次 | 操作前 (currentWeight) | 选中 | 操作后 |
|
||||
| ---- | ---------------------- | ----- | --------------- |
|
||||
| 初始 | A=0, B=0, C=0 | — | — |
|
||||
| 1 | A=5, B=1, C=1 | **A** | A=−2, B=1, C=1 |
|
||||
| 2 | A=3, B=2, C=2 | **A** | A=−4, B=2, C=2 |
|
||||
| 3 | A=1, B=3, C=3 | **B** | A=1, B=−4, C=3 |
|
||||
| 4 | A=6, B=−3, C=4 | **A** | A=−1, B=−3, C=4 |
|
||||
| 5 | A=4, B=−2, C=5 | **C** | A=4, B=−2, C=−2 |
|
||||
| 6 | A=9, B=−1, C=−1 | **A** | A=2, B=−1, C=−1 |
|
||||
| 7 | A=7, B=0, C=0 | **A** | A=0, B=0, C=0 |
|
||||
|
||||
|
||||
|
||||
@@ -210,3 +210,54 @@ func TestJson(t *testing.T) {
|
||||
1. **小请求(配置、JSON)**:使用 `io.ReadAll` 存入内存,再通过 `io.NopCloser` 塞回 `r.Body` 或设置 `r.GetBody`。
|
||||
2. **中等请求(签名校验)**:使用 `io.TeeReader` 边读边处理,节省一次全量扫描。
|
||||
3. **大请求(文件上传)**:**禁止 ReadAll**。直接流式 `io.Copy` 到目的地,或使用临时文件做中转。
|
||||
|
||||
|
||||
|
||||
## map的坑
|
||||
|
||||
go的map内部是哈希表,元素会因 rehash(扩容)而移动到新的内存位置,如果允许 `&m[key]` 拿到一个指针,map 一旦扩容,这个指针就变成悬空指针(指向已失效的内存),为了避免这种内存安全问题,Go 直接禁止对 map 值取地址,下面是示例代码:
|
||||
|
||||
```go
|
||||
type User struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func main() {
|
||||
m := map[int]User{1: {Name: "张三", Age: 20}}
|
||||
|
||||
// ❌ 编译错误:cannot assign to struct field m[1].Name in map
|
||||
m[1].Name = "李四"
|
||||
|
||||
// ✅ 正确的替代写法
|
||||
temp:=m[1]
|
||||
temp.Name = "李四"
|
||||
m[1]=temp
|
||||
}
|
||||
```
|
||||
|
||||
> **可寻址(addressable)**:能通过 `&` 拿到它内存地址的操作数。
|
||||
>
|
||||
> **不可寻址(not addressable)**:不能通过 `&` 拿到地址的操作数。
|
||||
|
||||
## 句点引入
|
||||
|
||||
一个完整引入声明语句形式的引入名`importname`可以是一个句点(`.`)。 这样的引入称为句点引入。使用被句点引入的包中的导出代码要素时,限定标识符的前缀必须省略。
|
||||
|
||||
比如在下面这个例子中,`Println`和`Now`函数调用不需要带任何前缀。
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
. "fmt"
|
||||
. "time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
Println("Current time:", Now())
|
||||
}
|
||||
```
|
||||
|
||||
> 一般来说,句点引入不推荐使用,因为它们会导致较低的代码可读性
|
||||
|
||||
|
||||
Reference in New Issue
Block a user