并发编程 第2阶段·第2/7课
package main
import ("fmt";"sync")
func main() {
fmt.Println("=== 无缓冲channel ===")
ch:=make(chan string);go func(){ch<-"hello"}();fmt.Printf("收到:%s\n",<-ch)
fmt.Println("\n=== 缓冲channel ===")
buf:=make(chan int,3);buf<-1;buf<-2;buf<-3;fmt.Printf("len=%d cap=%d\n",len(buf),cap(buf))
fmt.Printf("接收:%d %d %d\n",<-buf,<-buf,<-buf)
fmt.Println("\n=== 遍历 ===")
ch2:=make(chan int,5);go func(){for i:=1;i<=5;i++{ch2<-i};close(ch2)}()
for v:=range ch2{fmt.Printf("%d ",v)};fmt.Println()
fmt.Println("\n=== 单向 ===")
sender:=func(ch chan<- int){ch<-42};receiver:=func(ch <-chan int)int{return <-ch}
ch3:=make(chan int,1);sender(ch3);fmt.Printf("单向:%d\n",receiver(ch3))
fmt.Println("\n=== 生产者消费者 ===")
jobs:=make(chan int,10);results:=make(chan int,10)
go func(){for i:=0;i<10;i++{jobs<-i};close(jobs)}()
var wg sync.WaitGroup
for w:=0;w<3;w++{wg.Add(1);go func(id int){defer wg.Done();for j:=range jobs{fmt.Printf(" w%d:j%d\n",id,j);results<-j*2}}(w)}
go func(){wg.Wait();close(results)}()
c:=0;for range results{c++};fmt.Printf("处理%d个\n",c)
}
✅ 验证通过 — 实机运行结果:
=== 无缓冲channel ===
收到:hello
=== 缓冲channel ===
len=3 cap=3
接收:1 2 3
=== 遍历 ===
1 2 3 4 5
=== 单向 ===
单向:42
=== 生产者消费者 ===
w0:j0
w0:j1
w0:j2
w0:j3
w0:j4
w0:j5
w0:j6
w0:j7
w0:j8
w0:j9
处理10个
| 操作 | 无缓冲 | 缓冲 | nil | closed |
|---|---|---|---|---|
| 发送 | 阻塞 | 成功 | 永久阻塞 | panic |
| 接收 | 阻塞 | 成功 | 永久阻塞 | 零值 |
| 知识点 | 关键内容 |
|---|---|
| 无缓冲 | 同步通信 |
| 缓冲 | make(chan T,N) |
| 单向 | chan<-/<-chan |
| 关闭 | close/遍历range |
| 行为 | nil阻塞/closed panic |
生成→过滤→平方
缓冲channel限流
1→3→1模式
go doc查看标准库文档// 1. 预分配切片容量
s := make([]int, 0, expectedSize)
// 2. 使用strings.Builder拼接
var b strings.Builder
b.WriteString("hello")
// 3. 对象池复用
var bufPool = sync.Pool{New: func() interface{} { return new(bytes.Buffer) }}
// 4. 减少逃逸分析
// 小对象栈分配,大对象堆分配
// 5. benchmark测试
func BenchmarkXxx(b *testing.B) {
for i := 0; i < b.N; i++ { ... }
}
// 1. fmt.Printf格式化
fmt.Printf("%+v
", struct) // 带字段名
fmt.Printf("%#v
", value) // Go语法
// 2. log包
log.Printf("debug: value=%v", val)
// 3. delve调试器
// dlv debug ./main.go
// 4. pprof性能分析
import _ "net/http/pprof"
go http.ListenAndServe(":6060", nil)
go doc fmt.Printf 查看标准库文档go test 验证你的理解是否正确// 1. 预分配切片容量 — 避免频繁扩容
s := make([]int, 0, expectedSize)
// 2. strings.Builder拼接 — 比fmt.Sprintf快3-5倍
var b strings.Builder
b.WriteString("hello")
b.WriteString(" world")
result := b.String()
// 3. sync.Pool对象复用 — 减少GC压力
var bufPool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
}
buf := bufPool.Get().(*bytes.Buffer)
defer bufPool.Put(buf)
// 4. 减少堆分配 — 小对象栈分配,避免逃逸
// 用 go build -gcflags="-m" 分析逃逸
// 5. 使用benchmark验证性能
func BenchmarkXxx(b *testing.B) {
for i := 0; i < b.N; i++ {
// 被测代码
}
}
// go test -bench=. -benchmem
// 1. 格式化调试输出
fmt.Printf("%+v
", myStruct) // 带字段名
fmt.Printf("%#v
", myValue) // Go语法表示
// 2. log包运行时日志
log.Printf("[DEBUG] value=%v", val)
log.SetFlags(log.LstdFlags | log.Lshortfile)
// 3. delve源码调试器
// 安装: go install github.com/go-delve/delve/cmd/dlv@latest
// 使用: dlv debug ./main.go
// 命令: break main.main / continue / next / print
// 4. pprof性能分析
import _ "net/http/pprof"
go http.ListenAndServe(":6060", nil)
// 访问: http://localhost:6060/debug/pprof/
// 命令: go tool pprof http://localhost:6060/debug/pprof/profile
// 5. race detector竞态检测
// go run -race main.go
// go test -race ./...
| 工具 | 用途 | 安装 |
|---|---|---|
| golangci-lint | 代码静态检查 | go install github.com/golangci/golangci-lint/cmd/...@latest |
| gofumpt | 代码格式化(增强) | go install mvdan.cc/gofumpt@latest |
| goimports | 自动管理import | go install golang.org/x/tools/cmd/goimports@latest |
| dlv | 源码调试器 | go install github.com/go-delve/delve/cmd/dlv@latest |
| air | 热重载开发 | go install github.com/cosmtrek/air@latest |
| swag | Swagger文档生成 | go install github.com/swaggo/swag/cmd/swag@latest |
| migrate | 数据库迁移 | go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest |
myproject/
├── cmd/ # 可执行程序入口
│ └── server/
│ └── main.go
├── internal/ # 私有代码(不可外部导入)
│ ├── handler/ # HTTP处理
│ ├── service/ # 业务逻辑
│ ├── repository/ # 数据访问
│ └── model/ # 数据模型
├── pkg/ # 可复用公共包
│ └── utils/
├── api/ # API定义(proto/openapi)
├── configs/ # 配置文件
├── scripts/ # 构建/部署脚本
├── test/ # 集成测试
├── go.mod
├── go.sum
├── Makefile
└── Dockerfile
| 类别 | 推荐方案 | 替代方案 |
|---|---|---|
| Web框架 | Gin | Echo / Chi / Fiber |
| ORM | GORM | Ent / sqlx / sqlc |
| 配置 | Viper | koanf |
| 日志 | zap | zerolog / slog |
| 验证 | validator | go-playground/validator |
| 缓存 | go-redis | redigo |
| JWT | golang-jwt | — |
| Swagger | swag | — |
| 测试 | testify | — |
| Mock | gomock | testify/mock |
// 命名规范
// 包名: 小写单词, 不用下划线 package httputil
// 导出: 大写开头 func CreateUser()
// 未导出: 小写开头 func validateInput()
// 接口: -er后缀 type Reader interface{}
// 常量: 驼峰 const maxRetries = 3
// 枚举: 类型+常量 type Role int; const Admin Role = 0
// 错误处理规范
// 错误变量: Err前缀 var ErrNotFound = errors.New("...")
// 错误类型: Error后缀 type ValidationError struct{...}
// 包装: %w fmt.Errorf("查询失败: %w", err)
// 注释规范
// 导出符号必须有注释
// 注释以符号名开头 // CreateUser creates a new user.
// 包注释: doc.go // Package user handles user operations.
// 1. 输入验证 — 永远不信任用户输入
// 2. SQL注入 — 使用参数化查询
db.Query("SELECT * FROM users WHERE id = $1", id) // ✅
db.Query("SELECT * FROM users WHERE id = " + id) // ❌
// 3. XSS防护 — HTML转义
template.HTML(escape(userInput)) // 或使用html/template自动转义
// 4. CSRF — 使用token验证
// 5. 密码 — bcrypt/argon2哈希, 永不明文存储
hashed, _ := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)
// 6. HTTPS — 生产环境必须
// 7. 日志脱敏 — 不记录密码/Token
log.Printf("user login: id=%d", userID) // ✅
log.Printf("password=%s", pwd) // ❌
// go.mod最佳实践
module github.com/yourorg/yourproject
go 1.22
// 直接依赖 — 项目直接使用的包
require (
github.com/gin-gonic/gin v1.9.1
gorm.io/gorm v1.25.0
)
// 间接依赖 — 自动管理, 不要手动编辑
require (
github.com/json-iterator/go v1.1.12 // indirect
)
// 替换 — 本地开发/ fork修复
replace github.com/original/pkg => ../local-fork
// 排除 — 排除有问题的版本
exclude github.com/broken/pkg v1.0.0