跳到主要内容

PotPlayer 快捷键

· 阅读需 2 分钟
素明诚
Full stack development

常用快捷键​

功能快捷键
播放/暂停空格键
停止X
下一帧D
上一帧E
快进 10 秒→
快退 10 秒←
快进 30 秒Ctrl + →
快退 30 秒Ctrl + ←
快进 1 分钟Alt + →
快退 1 分钟Alt + ←
增加播放速度C
减少播放速度X
恢复正常速度Z
增加音量↑
减少音量↓
静音M
显示/隐藏字幕Ctrl + Alt + H
切换字幕Alt + L
下一字幕Ctrl + L
上一字幕Ctrl + Shift + L
打开文件Ctrl + O
打开网址Ctrl + U
打开文件夹Ctrl + F
截图Ctrl + E
全屏Enter 或 Alt + Enter
退出全屏Esc
画面尺寸 - 原始1
画面尺寸 - 50%2
画面尺寸 - 100%3
画面尺寸 - 150%4
画面尺寸 - 200%5
比例 - 16:9F5
比例 - 4:3F6
比例 - 1.85:1F7
比例 - 2.35:1F8
旋转 - 顺时针 90 度Ctrl + Shift + 3
旋转 - 逆时针 90 度Ctrl + Shift + 1
播放列表 - 打开F6
播放列表 - 清空Ctrl + Shift + L
播放列表 - 保存Ctrl + S
跳转 - 到上一个播放点Alt + P
跳转 - 到下一个播放点Alt + N
循环播放R
随机播放S

要详细查看所有快捷键并进行自定义,可以在 PotPlayer 中通过以下路径进行查看和修改

  1. 打开 PotPlayer。
  2. 点击右上角的菜单按钮(或按 F5 打开设置)。
  3. 在设置菜单中,选择 快捷键 选项。

下载地址​

https://potplayer.daum.net/

如何编写 Go 语言的单元测试

· 阅读需 2 分钟
素明诚
Full stack development

testing 包​

testing 包是 Go 语言的标准库组成部分,专门用于支持自动化测试。该包提供了丰富的功能,允许开发者定义测试用例、记录测试结果,并利用一系列工具函数控制测试逻辑和报告测试状态。这包括处理失败、日志记录和条件性测试中断等功能。

示例代码​

以一个基本的加法函数测试为例。首先,假设你有一个加法函数定义在 calculator.go 文件中

package calculator
​
// Add 返回两个整数的和
func Add(a, b int) int {
return a + b
}

对应的测试文件 calculator_test.go 包含如下代码

package calculator
​
import "testing"
​
// TestAdd 测试 Add 函数
func TestAdd(t *testing.T) {
result := Add(1, 2)
expected := 3
if result != expected {
t.Errorf("Add(1, 2) = %d; expected %d", result, expected)
}
}

编写测试的规则​

测试文件名应以 _test.go 结尾,存放在与被测试源文件相同的包中。每个测试函数必须以 Test 开头,并接受一个 *testing.T 类型的参数。这些函数可以使用 testing 包提供的方法进行错误报告和日志记录

  • t.Errorf() 和 t.Error(): 当测试需要报告错误时使用,Errorf 允许按格式输出。
  • t.Fatalf() 和 t.Fatal(): 遇到无法继续的错误时调用,会立即终止测试。
  • t.Log() 和 t.Logf(): 用于记录测试信息,这些信息在使用 -v 参数运行测试时显示。

运行测试​

打开命令行或终端,在包含测试文件的目录下运行

go test

使用 -v 参数可以查看每个测试函数的详细输出信息。若只想运行特定的测试,可以使用 -run 参数,如

go test -run TestAdd

如何编写 Go 语言的性能测试

· 阅读需 1 分钟
素明诚
Full stack development

testing 包​

testing 包提供了一个专门用于性能测试的工具,称为基准测试(benchmarks)。基准测试函数以 Benchmark 开头,并接受一个 *testing.B 类型的参数。这个参数提供了控制测试运行的方法和属性,例如 b.N,它代表测试循环的次数。

示例代码​

package main
​
import (
"encoding/json"
"github.com/bytedance/sonic"
)
​
type Student struct {
Name string
Age int
Gender string
}
​
type Class struct {
Id string
Students []Student
}
​
var (
s = Student{"张三", 18, "女"}
c = Class{
Id: "1年2班",
Students: []Student{s, s, s},
}
)
// Benchmark 开头
func
Json(b *testing.B) {
for i := 0; i < b.N; i++ {
bytes, _ := json.Marshal(c)
var c2 Class
json.Unmarshal(bytes, &c2)
}
}
​
func BenchmarkSonic(b *testing.B) {
for i := 0; i < b.N; i++ {
bytes, _ := sonic.Marshal(c)
var c2 Class
sonic.Unmarshal(bytes, &c2)
}
}

IDE 执行​

44c617759eee959e35e5c76c15fb67df### 命令行执行

打开命令行或终端,在包含性能测试文件的目录下运行:

go test -bench=.

使用 -bench 参数可以指定要运行的基准测试。-bench=. 表示运行所有基准测试。

监控单机Docker容器使用cAdvisorPrometheus和Grafana

· 阅读需 1 分钟
素明诚
Full stack development

docker-compose.yml​

services:
prometheus:
image: prom/prometheus:v2.53.0
container_name: prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
ports:
- "59090:9090"
networks:
- monitor-net
restart: unless-stopped
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.enable-lifecycle'
depends_on:
- cadvisor
logging:
driver: json-file
options:
max-size: "200m"
max-file: "10"
grafana:
image: grafana/grafana:10.4.4
container_name: grafana
volumes:
- grafana_data:/var/lib/grafana
- ./grafana.ini:/etc/grafana/grafana.ini # Grafana 配置文件
environment:
GF_SECURITY_ADMIN_PASSWORD: admin123456 # 管理员密码
GF_USERS_ALLOW_SIGN_UP: "false" # 禁止用户自行注册
ports:
- "53000:3000"
networks:
- monitor-net
restart: unless-stopped
depends_on:
- prometheus
logging:
driver: json-file
options:
max-size: "200m"
max-file: "10"
cadvisor:
image: gcr.io/cadvisor/cadvisor
container_name: cadvisor
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
ports:
- "58080:8080"
networks:
- monitor-net
restart: unless-stopped
logging:
driver: json-file
options:
max-size: "100m"
max-file: "5"
volumes:
prometheus_data:
driver: local
grafana_data:
driver: local
networks:
monitor-net:
driver: bridge

prometheus.yml​

scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['prometheus:9090'] # 使用 Docker Compose 服务名和内部端口
- job_name: 'cadvisor'
scrape_interval: 5s
static_configs:
- targets: ['cadvisor:8080'] # 使用 Docker Compose 服务名和内部端口

grafana 配置​

添加数据源:prometheus

设置 prometheus 的 Connection 为 http://prometheus:9090 保存

面板使用​

a99b4cb38396d462a5825c43f5c55e8d

Linux 命令行实用的小技巧

· 阅读需 3 分钟
素明诚
Full stack development

重复上一个命令

  • 输入 !! 并按回车,快速执行上一条命令。

重用上一个命令的最后一个参数

  • 输入 !$ 可以在新命令中使用上一个命令的最后一个参数。

快速创建或删除多个文件夹

  • 使用 mkdir folder1 folder2 folder3 同时创建多个文件夹。
  • 使用 rm -r folder1 folder2 folder3 一次性删除多个文件夹及其内容。

搜索命令历史

  • 按 ctrl+r 开始输入搜索历史命令,继续按 ctrl+r 可查看更多匹配的历史命令。

创建命令别名

  • 对于经常使用的长命令,可以使用 alias 创建一个简短的别名,例如 alias ll='ls -la'。
  • 取消使用 unalias ll,重载配置 source ~/.bashrc

暂停和继续进程

  • 使用 ctrl+z 暂停当前进程,使用 fg 将其恢复到前台继续运行。

定时执行命令并显示结果

  • 使用 watch 命令定时执行其他命令,并实时显示结果,例如 watch -n 10 df -h 每 10 秒检查一次磁盘使用情况。
  • 60 秒后自动终止 watch 命令timeout 60 watch -n 10 df -h

快速切换回之前的目录

  • 使用 cd - 快速返回到之前的目录。

批量重命名或移动文件

  • 使用 rename 's/.txt/.bak/' *.txt 将所有 .txt 文件扩展名改为 .bak。

倒序输出文件内容

  • 使用 tac 命令可以倒序显示文件内容,适用于查看日志文件。

搜索内容并高亮显示

  • 使用 grep --color 'text' filename 可以高亮显示匹配的文本。

管理多个会话

  • 使用 screen 或 tmux 可以在一个窗口中开启多个会话,适合同时运行多个命令行程序。

在后台运行程序并忽略挂起信号

  • 使用 nohup command & 可以让程序在退出终端后继续运行。

快速删除大量文件

  • 使用 find . -type f -name 'pattern' -delete 可以更高效地删除大量文件。

设置环境变量的默认值

  • 使用 ${VAR:-default} 在变量未设置或为空时提供一个默认值。

比较两个文件的不同

  • 使用 diff 快速识别两个文件之间的差异。
  • diff -u version1.txt version2.txt。这将输出两个文件内容的差异,并使用 -u 选项格式显示上下文,帮助你理解每处差异的前后关系。

监控文件变化

  • 使用 tail -f filename 实时监控文件末尾部分的变化,非常适合实时查看正在写入的日志文件。

Go fmt 格式化输出

· 阅读需 2 分钟
素明诚
Full stack development

基本格式化占位符​

占位符描述
%v默认格式输出变量的值。结构体时输出字段值。
%+v输出结构体时包括字段名和字段值。
%#v输出值的 Go 语法表示,即源代码片段。
%T输出值的类型。
%d, %b, %o, %x, %X分别表示整数的十进制、二进制、八进制、小写十六进制和大写十六进制格式。
%f, %e, %E, %g, %G分别表示浮点数的默认格式、小写和大写的科学计数法、最短表示法(自动选择 %e 或 %f)。
%s输出字符串。
%q输出双引号围绕的由 Go 语法安全转义的字符串。
%p输出指针的地址(十六进制)。
%c输出字符(Unicode 码点)。

格式控制选项​

选项描述
%9d宽度为 9 的十进制数,右对齐。
%.2f浮点数,小数点后只保留两位。
%9.2f, %-9.2f宽度为 9,小数点后保留两位的浮点数,分别右对齐和左对齐。
%09d宽度为 9 的十进制数,空白处用零填充。
%+d输出整型数时,显示符号(正数显示 +,负数显示 -)。
% 6d宽度至少为 6,不足部分以空格填充。

注意事项​

类型匹配:确保占位符与变量类型匹配,防止类型错误。

精度与宽度:合理设置精度和宽度,注意过小的宽度不会截断输出,而过小的精度可能导致数据丢失。

性能考虑:频繁使用字符串格式化会影响程序性能,尤其是在数据处理和循环中。

Go 语言中 defer 语句

· 阅读需 1 分钟
素明诚
Full stack development

Go 语言中,defer 语句遵循后进先出(LIFO)的原则执行。这样做主要是为了简化资源(如文件、锁)的管理,使得资源的获取和释放顺序保持一致,易于维护。

package main

import (
"fmt"
)

func main() {
defer fmt.Println("第一个 defer") // 最后执行
defer fmt.Println("第二个 defer") // 第二个执行
defer fmt.Println("第三个 defer") // 最先执行

fmt.Println("主体")
}

本质原因就是因为 defer 语句使用了栈来存储

defer 与 匿名函数​

使用 defer 匿名函数时,核心问题在于变量捕获特性

package main

import "fmt"

func main() {
a := 1
defer func() {
fmt.Println(a) // 输出 2
}()
a = 2
fmt.Println(a) // 输出 2
}

defer 后面如果是 go 语句,这个 go 语句里面的变量,在注册的时候就已经计算好了

defer 后面如果是匿名函数,这个匿名函数设计到的变量,是在执行的时候才会计算。

Go 语言中切片的声明初始化和操作详解

· 阅读需 2 分钟
素明诚
Full stack development

声明切片变量​

声明:当声明一个切片变量如 var s []int 时,s 初始化为 nil,表示它没有指向任何底层数组。其长度 (len) 和容量 (cap) 都为 0,无法访问或修改任何元素,因为实际上还没有底层数组与之关联。

使用 make 函数创建切片​

内存分配:调用 make([]int, 3, 5) 时,底层会为切片分配一个长度(容量)为 5 的整型数组。这个数组是在堆上分配的,以便动态管理内存,允许切片在运行时调整大小。

初始化切片结构:切片结构体的实例会在栈上创建,包含三个关键的字段

  • Pointer:指向已分配底层数组的第一个元素的指针。
  • Len:设置为指定的长度,此例中为 3,意味着切片当前访问到的元素数量。
  • Cap:设置为数组的总容量,此例中为 5,即最多可以扩展到的元素数量。

初始化数组元素:新分配的数组元素初始化为其类型的零值。对于 int 类型,每个元素都初始化为 0。

使用字面量初始化切片​

内存分配:使用字面量如 s := []int{1, 2, 3} 初始化切片时,底层同样会在堆上分配一个容纳 3 个整型元素的数组。

初始化切片结构:创建的切片结构体实例指向这个数组,长度和容量都设置为字面量中元素的数量,即 3。

填充数组元素:数组中的元素将直接使用提供的字面值(1, 2, 3)进行初始化,不使用零值。

切片操作​

创建新切片:当执行 s2 := s[1:3] 的切片操作时,底层不会复制数组,而是创建一个新的切片结构体,指向原切片 s 的底层数组的第 2 个元素(索引 1)。

新切片属性

  • Len:新切片的长度为 2,因为它从索引 1 到索引 2,包含 2 个元素。
  • Cap:新切片的容量为 4,计算方式为原切片的容量 5 减去新切片的起始索引 1。

Linux 运行 go 文件

· 阅读需 1 分钟
素明诚
Full stack development
package main

import "fmt"

func main(){
fmt.Println("hello")
}

直接运行​

go run hello.go

编译后运行​

go build hello.go
./hello

直接运行和编译后运行的区别​

直接运行 (go run): 这个命令会在内部先编译程序成一个临时文件,然后立即执行这个编译后的文件。它适合于开发过程中快速测试和调试代码,因为它省去了手动编译的步骤。

编译后运行 (go build): 这个命令会将你的 Go 源代码编译成一个可执行文件。在编译过程中,Go 编译器会优化代码,从而使最终的可执行文件在运行时拥有更好的性能。编译完成后,你可以多次运行这个可执行文件而无需再次编译,这对于生产环境非常重要。

Docker 镜像优化策略

· 阅读需 2 分钟
素明诚
Full stack development

1. 选择小型基础镜像​

选择 Alpine Linux 等小型基础镜像,因其体积小巧,有助于减少最终镜像的大小。

2. 最小化层的数量​

通过合并多个 RUN 指令,减少镜像层数,例如将更新、安装和清理步骤合并到一个 RUN 中执行。

RUN apt-get update && \
apt-get install -y package1 package2 && \
rm -rf /var/lib/apt/lists/*

3. 清理不必要的文件​

在安装软件包后,清理缓存和临时文件,移除不必要的包,以减少镜像的体积,配合多阶段构建。

4. 使用多阶段构建​

通过多阶段构建,只在最终镜像中包含运行应用所必需的文件和依赖,从而减少镜像大小。

# Build stage
FROM golang:1.16 as builder
WORKDIR /app
COPY . .
RUN go build -o myapp .
​
# Final stage
FROM alpine:latest
COPY --from=builder /app/myapp /myapp
ENTRYPOINT ["./myapp"]

5. 使用.dockerignore 文件​

利用 .dockerignore 文件排除不必要的文件和目录,防止它们被添加到镜像中。

6. 优化指令顺序​

通过优化 Dockerfile 中指令的顺序,使得不经常变更的指令尽量放在前面,以利用 Docker 的构建缓存。

7. 精简健康检查指令​

确保健康检查(HEALTHCHECK)指令尽可能轻量,不增加额外的负担。

8. 选择性拷贝文件​

在使用 COPY 指令时,只拷贝必需的文件,避免引入不必要的数据。

9. 有效利用构建缓存​

合理安排 Dockerfile 中的指令,以最大限度地复用构建缓存,减少不必要的重建过程。

10. 审查软件包安装​

定期审查和更新 Dockerfile,移除不再需要的依赖,保持镜像的轻量级。

11. 压缩应用程序文件​

对静态资源进行压缩处理,如使用 Gzip 压缩,以减小文件占用的空间。

12. 使用非 root 用户​

指定非 root 用户运行容器,减少对安全特性的依赖,可能带来的额外文件或库。

通过实施以上策略,可以有效控制 Docker 镜像的大小,提升容器的启动速度和运行效率,降低资源消耗,优化容器的整体性能。