feat(auth): 添加完整的用户认证API项目
- 实现用户注册、登录、JWT令牌认证功能 - 集成Gin、GORM、Viper、Zap等框架 - 添加密码加密、数据库操作、中间件等完整功能 - 配置多环境支持、日志轮转、CORS处理 - 创建完整的项目结构和配置文件体系
This commit is contained in:
3
go并发模型/01go-goroutine-gpm/go.mod
Normal file
3
go并发模型/01go-goroutine-gpm/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module go-goroutine-gpm
|
||||
|
||||
go 1.22.2
|
||||
76
go并发模型/01go-goroutine-gpm/main.go
Normal file
76
go并发模型/01go-goroutine-gpm/main.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func say(s string, id int) {
|
||||
for i := 0; i < 3; i++ {
|
||||
fmt.Printf("[%d] %s: step %d\n", id, s, i)
|
||||
time.Sleep(100 * time.Millisecond) // 模拟工作
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 1. 单线程顺序执行 ===")
|
||||
say("Hello", 1)
|
||||
say("World", 2)
|
||||
|
||||
fmt.Println("\n=== 2. 使用 Goroutine 并发执行 ===")
|
||||
go say("Goroutine-A", 1)
|
||||
go say("Goroutine-B", 2)
|
||||
|
||||
// 主 goroutine 等待 1 秒,否则程序会提前退出
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
fmt.Println("\n=== 3. 使用 sync.WaitGroup 安全等待 ===")
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for i := 1; i <= 3; i++ {
|
||||
wg.Add(1)
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
fmt.Printf("Worker %d started\n", id)
|
||||
time.Sleep(time.Duration(id*200) * time.Millisecond)
|
||||
fmt.Printf("Worker %d finished\n", id)
|
||||
}(i)
|
||||
}
|
||||
|
||||
wg.Wait() // 阻塞直到所有 goroutine 完成
|
||||
fmt.Println("All workers done!")
|
||||
|
||||
fmt.Println("\n=== 4. 查看当前 GOMAXPROCS 和 CPU 核心数 ===")
|
||||
fmt.Printf("CPU 核心数: %d\n", runtime.NumCPU())
|
||||
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0)) // 0 表示不修改,仅查询
|
||||
|
||||
fmt.Println("\n=== 5. 手动设置 GOMAXPROCS(通常不需要)===")
|
||||
old := runtime.GOMAXPROCS(2)
|
||||
fmt.Printf("旧 GOMAXPROCS: %d, 新设为: 2\n", old)
|
||||
runtime.GOMAXPROCS(old) // 恢复原值
|
||||
|
||||
fmt.Println("\n=== 6. 观察 Goroutine 数量变化 ===")
|
||||
fmt.Printf("启动前 Goroutine 数: %d\n", runtime.NumGoroutine())
|
||||
|
||||
var wg2 sync.WaitGroup
|
||||
for i := 0; i < 5; i++ {
|
||||
wg2.Add(1)
|
||||
go func(n int) {
|
||||
defer wg2.Done()
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}(i)
|
||||
}
|
||||
|
||||
time.Sleep(50 * time.Millisecond) // 让 goroutine 启动
|
||||
fmt.Printf("启动后 Goroutine 数: %d\n", runtime.NumGoroutine())
|
||||
|
||||
wg2.Wait()
|
||||
fmt.Printf("全部完成后 Goroutine 数: %d\n", runtime.NumGoroutine())
|
||||
|
||||
// 在程序最后添加
|
||||
time.Sleep(1 * time.Second)
|
||||
fmt.Printf("延迟后 Goroutine 数: %d\n", runtime.NumGoroutine())
|
||||
|
||||
}
|
||||
35
go并发模型/02go-channel-practice/buffered.go
Normal file
35
go并发模型/02go-channel-practice/buffered.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ch := make(chan int, 3) // 容量为 3 的有缓冲 channel
|
||||
|
||||
fmt.Println("[Main] 开始发送 3 个元素...")
|
||||
ch <- 1
|
||||
fmt.Println("[Main] 已发送 1")
|
||||
ch <- 2
|
||||
fmt.Println("[Main] 已发送 2")
|
||||
ch <- 3
|
||||
fmt.Println("[Main] 已发送 3 (已满)")
|
||||
|
||||
// 再发送一个会怎样?
|
||||
go func() {
|
||||
fmt.Println("[Sender] 尝试发送第 4 个元素(会阻塞,直到有接收者)...")
|
||||
ch <- 4
|
||||
fmt.Println("[Sender] 第 4 个元素发送成功")
|
||||
}()
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
fmt.Println("[Main] 开始接收...")
|
||||
for i := 0; i < 4; i++ {
|
||||
v := <-ch
|
||||
fmt.Println("[Main] 收到:", v)
|
||||
}
|
||||
|
||||
fmt.Println("[Main] 程序结束")
|
||||
}
|
||||
28
go并发模型/02go-channel-practice/directional.go
Normal file
28
go并发模型/02go-channel-practice/directional.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// 只负责发送数据
|
||||
func producer(out chan<- int) {
|
||||
for i := 1; i <= 5; i++ {
|
||||
fmt.Println("[Producer] 发送:", i)
|
||||
out <- i
|
||||
}
|
||||
fmt.Println("[Producer] 关闭 channel")
|
||||
close(out) // 只有发送方才能关闭
|
||||
}
|
||||
|
||||
// 只负责接收数据
|
||||
func consumer(in <-chan int) {
|
||||
for v := range in { // 直到 channel 被关闭
|
||||
fmt.Println("[Consumer] 接收:", v)
|
||||
}
|
||||
fmt.Println("[Consumer] channel 已关闭,接收结束")
|
||||
}
|
||||
|
||||
func main() {
|
||||
ch := make(chan int)
|
||||
|
||||
go producer(ch) // ch 在这里被当作 只发送 channel 使用
|
||||
consumer(ch) // ch 在这里被当作 只接收 channel 使用
|
||||
}
|
||||
3
go并发模型/02go-channel-practice/go.mod
Normal file
3
go并发模型/02go-channel-practice/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module go-channel-practice
|
||||
|
||||
go 1.22.2
|
||||
37
go并发模型/02go-channel-practice/pipeline.go
Normal file
37
go并发模型/02go-channel-practice/pipeline.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
// 生产者:产生 1~5
|
||||
func producer1(out chan<- int) {
|
||||
for i := 1; i <= 5; i++ {
|
||||
fmt.Println("[Producer] 发送:", i)
|
||||
out <- i
|
||||
}
|
||||
close(out)
|
||||
}
|
||||
|
||||
// 处理者:把数字放大 10 倍
|
||||
func multiplier(in <-chan int, out chan<- int) {
|
||||
for v := range in {
|
||||
fmt.Println("[Multiplier] 接收:", v)
|
||||
out <- v * 10
|
||||
}
|
||||
close(out)
|
||||
}
|
||||
|
||||
// 消费者:打印结果
|
||||
func consumer1(in <-chan int) {
|
||||
for v := range in {
|
||||
fmt.Println("[Consumer] 最终结果:", v)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
ch1 := make(chan int, 2) // 有缓冲,减轻 producer 阻塞
|
||||
ch2 := make(chan int, 2)
|
||||
|
||||
go producer1(ch1)
|
||||
go multiplier(ch1, ch2)
|
||||
consumer1(ch2)
|
||||
}
|
||||
24
go并发模型/02go-channel-practice/unbuffered.go
Normal file
24
go并发模型/02go-channel-practice/unbuffered.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ch := make(chan string) // 无缓冲 channel
|
||||
|
||||
go func() {
|
||||
fmt.Println("[Sender] 准备发送数据...")
|
||||
ch <- "hello from goroutine" // 这里会阻塞,直到有人接收
|
||||
fmt.Println("[Sender] 数据发送完毕")
|
||||
}()
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
fmt.Println("[Main] 1 秒后开始接收数据...")
|
||||
|
||||
msg := <-ch // 接收数据,同时解除发送方阻塞
|
||||
fmt.Println("[Main] 收到:", msg)
|
||||
|
||||
fmt.Println("[Main] 程序结束")
|
||||
}
|
||||
3
go并发模型/03go-select-practice/go.mod
Normal file
3
go并发模型/03go-select-practice/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module go-select-practice
|
||||
|
||||
go 1.22.2
|
||||
33
go并发模型/03go-select-practice/select_basic.go
Normal file
33
go并发模型/03go-select-practice/select_basic.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ch1 := make(chan string)
|
||||
ch2 := make(chan string)
|
||||
|
||||
// 模拟两个不同来源的“数据源”
|
||||
go func() {
|
||||
time.Sleep(1 * time.Second)
|
||||
ch1 <- "result from ch1 (1s)"
|
||||
}()
|
||||
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
ch2 <- "result from ch2 (2s)"
|
||||
}()
|
||||
|
||||
fmt.Println("等待 ch1 或 ch2 的结果...(谁先来处理谁)")
|
||||
|
||||
select {
|
||||
case v := <-ch1:
|
||||
fmt.Println("收到 ch1:", v)
|
||||
case v := <-ch2:
|
||||
fmt.Println("收到 ch2:", v)
|
||||
}
|
||||
|
||||
fmt.Println("main 结束")
|
||||
}
|
||||
38
go并发模型/03go-select-practice/select_context.go
Normal file
38
go并发模型/03go-select-practice/select_context.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 模拟一个可被取消的操作
|
||||
func doWork(ctx context.Context) error {
|
||||
for i := 1; i <= 5; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// context 被取消或超时
|
||||
fmt.Println("doWork 被取消:", ctx.Err())
|
||||
return ctx.Err()
|
||||
default:
|
||||
fmt.Println("工作中 step", i)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
fmt.Println("doWork 正常完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
fmt.Println("开始工作,最长 3 秒...")
|
||||
|
||||
if err := doWork(ctx); err != nil {
|
||||
fmt.Println("结束,原因:", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("结束: 正常完成")
|
||||
}
|
||||
33
go并发模型/03go-select-practice/select_default.go
Normal file
33
go并发模型/03go-select-practice/select_default.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ch := make(chan int)
|
||||
|
||||
go func() {
|
||||
for i := 1; i <= 5; i++ {
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
ch <- i
|
||||
}
|
||||
close(ch)
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case v, ok := <-ch:
|
||||
if !ok {
|
||||
fmt.Println("channel 已关闭,退出循环")
|
||||
return
|
||||
}
|
||||
fmt.Println("收到:", v)
|
||||
default:
|
||||
// 没有数据可读时,做点“其他事”
|
||||
fmt.Println("没有新数据,先忙点别的...")
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
46
go并发模型/03go-select-practice/select_timeout.go
Normal file
46
go并发模型/03go-select-practice/select_timeout.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 模拟一个可能很慢的操作
|
||||
func slowOperation() (string, error) {
|
||||
time.Sleep(3 * time.Second) // 假设真的很慢
|
||||
return "slow result", nil
|
||||
}
|
||||
|
||||
func doWithTimeout(timeout time.Duration) (string, error) {
|
||||
resultCh := make(chan string, 1)
|
||||
errCh := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
res, err := slowOperation()
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
resultCh <- res
|
||||
}()
|
||||
|
||||
select {
|
||||
case res := <-resultCh:
|
||||
return res, nil
|
||||
case err := <-errCh:
|
||||
return "", err
|
||||
case <-time.After(timeout):
|
||||
return "", errors.New("操作超时")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("开始调用,最大等待 2 秒...")
|
||||
res, err := doWithTimeout(2 * time.Second)
|
||||
if err != nil {
|
||||
fmt.Println("失败:", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("成功:", res)
|
||||
}
|
||||
35
go并发模型/04go-context-practice/cancel_basic.go
Normal file
35
go并发模型/04go-context-practice/cancel_basic.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 模拟一个可被取消的循环任务
|
||||
func worker(ctx context.Context, name string) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
fmt.Println(name, "收到取消信号:", ctx.Err())
|
||||
return
|
||||
default:
|
||||
fmt.Println(name, "还在干活...")
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
go worker(ctx, "worker-1")
|
||||
go worker(ctx, "worker-2")
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
fmt.Println("main: 决定取消所有 worker")
|
||||
cancel() // 发出取消信号
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
fmt.Println("main 结束")
|
||||
}
|
||||
42
go并发模型/04go-context-practice/derived_context.go
Normal file
42
go并发模型/04go-context-practice/derived_context.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func subTask(ctx context.Context, name string, d time.Duration) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
fmt.Println(name, "提前被取消:", ctx.Err())
|
||||
case <-time.After(d):
|
||||
fmt.Println(name, "完成,用时", d)
|
||||
}
|
||||
}
|
||||
|
||||
func mainTask(ctx context.Context) {
|
||||
// 从上游 ctx 派生两个子 context
|
||||
ctx1, cancel1 := context.WithCancel(ctx)
|
||||
defer cancel1()
|
||||
|
||||
ctx2, cancel2 := context.WithTimeout(ctx, 2*time.Second)
|
||||
defer cancel2()
|
||||
|
||||
go subTask(ctx1, "subTask-1", 5*time.Second)
|
||||
go subTask(ctx2, "subTask-2", 5*time.Second)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
fmt.Println("mainTask: 主动取消 subTask-1 的 ctx1")
|
||||
cancel1()
|
||||
|
||||
// 等待一会儿,看 subTask-2 是否因超时被取消
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
|
||||
func main() {
|
||||
root := context.Background()
|
||||
fmt.Println("开始 mainTask...")
|
||||
mainTask(root)
|
||||
fmt.Println("main 结束")
|
||||
}
|
||||
3
go并发模型/04go-context-practice/go.mod
Normal file
3
go并发模型/04go-context-practice/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module go-context-practice
|
||||
|
||||
go 1.22.2
|
||||
37
go并发模型/04go-context-practice/timeout_with_context.go
Normal file
37
go并发模型/04go-context-practice/timeout_with_context.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 模拟一个可能很慢的操作
|
||||
func slowJob(ctx context.Context) error {
|
||||
for i := 1; i <= 5; i++ {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
fmt.Println("slowJob 被取消:", ctx.Err())
|
||||
return ctx.Err()
|
||||
default:
|
||||
fmt.Println("slowJob 进行中 step", i)
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
fmt.Println("slowJob 正常完成")
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
// 最多给 slowJob 3 秒时间
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
|
||||
fmt.Println("开始执行 slowJob,超时时间 3 秒...")
|
||||
if err := slowJob(ctx); err != nil {
|
||||
fmt.Println("结束,原因:", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("结束:正常完成")
|
||||
}
|
||||
3
go并发模型/05go-sync-practice/go.mod
Normal file
3
go并发模型/05go-sync-practice/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module go-sync-practice
|
||||
|
||||
go 1.22.2
|
||||
28
go并发模型/05go-sync-practice/mutex_counter.go
Normal file
28
go并发模型/05go-sync-practice/mutex_counter.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var wg sync.WaitGroup
|
||||
var mu sync.Mutex
|
||||
counter := 0
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < 1000; j++ {
|
||||
mu.Lock()
|
||||
counter++
|
||||
mu.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
fmt.Println("期待的结果:", 1000*1000)
|
||||
fmt.Println("实际结果:", counter)
|
||||
}
|
||||
25
go并发模型/05go-sync-practice/race_counter.go
Normal file
25
go并发模型/05go-sync-practice/race_counter.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var wg sync.WaitGroup
|
||||
counter := 0
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < 1000; j++ {
|
||||
counter++
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
fmt.Println("期待的结果:", 1000*1000)
|
||||
fmt.Println("实际结果:", counter)
|
||||
}
|
||||
55
go并发模型/05go-sync-practice/rwmutex_cache.go
Normal file
55
go并发模型/05go-sync-practice/rwmutex_cache.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Cache struct {
|
||||
mu sync.RWMutex
|
||||
data map[string]string
|
||||
}
|
||||
|
||||
func (c *Cache) Get(key string) string {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
return c.data[key]
|
||||
}
|
||||
|
||||
func (c *Cache) Set(key, value string) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
c.data[key] = value
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := &Cache{data: make(map[string]string)}
|
||||
c.Set("foo", "bar")
|
||||
|
||||
var wg sync.WaitGroup
|
||||
|
||||
// 多个读 goroutine
|
||||
for i := 0; i < 5; i++ {
|
||||
wg.Add(1)
|
||||
go func(id int) {
|
||||
defer wg.Done()
|
||||
for j := 0; j < 5; j++ {
|
||||
v := c.Get("foo")
|
||||
fmt.Printf("reader-%d 第 %d 次读到: %s\n", id, j, v)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
|
||||
// 一个写 goroutine
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
time.Sleep(300 * time.Millisecond)
|
||||
fmt.Println("writer: 更新 foo -> baz")
|
||||
c.Set("foo", "baz")
|
||||
}()
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
29
go并发模型/05go-sync-practice/waitgroup_like_latch.go
Normal file
29
go并发模型/05go-sync-practice/waitgroup_like_latch.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func worker(id int, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
fmt.Printf("worker-%d 开始工作\n", id)
|
||||
time.Sleep(time.Duration(id) * 300 * time.Millisecond)
|
||||
fmt.Printf("worker-%d 完成\n", id)
|
||||
}
|
||||
|
||||
func main() {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
n := 3
|
||||
wg.Add(n)
|
||||
|
||||
for i := 1; i <= n; i++ {
|
||||
go worker(i, &wg)
|
||||
}
|
||||
|
||||
fmt.Println("main: 等待所有 worker 完成...")
|
||||
wg.Wait()
|
||||
fmt.Println("main: 全部完成")
|
||||
}
|
||||
16
go并发模型/06go-atomic-cpu/atomic_cas.go
Normal file
16
go并发模型/06go-atomic-cpu/atomic_cas.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var value int64 = 0
|
||||
|
||||
success := atomic.CompareAndSwapInt64(&value, 0, 42)
|
||||
fmt.Println("第一次 CAS 是否成功:", success, "当前值:", value)
|
||||
|
||||
success = atomic.CompareAndSwapInt64(&value, 0, 100)
|
||||
fmt.Println("第二次 CAS 是否成功:", success, "当前值:", value)
|
||||
}
|
||||
26
go并发模型/06go-atomic-cpu/atomic_counter.go
Normal file
26
go并发模型/06go-atomic-cpu/atomic_counter.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var wg sync.WaitGroup
|
||||
var counter int64 // 注意必须是 int64/uint64 等特定类型
|
||||
|
||||
for i := 0; i < 1000; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < 1000; j++ {
|
||||
atomic.AddInt64(&counter, 1)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
fmt.Println("期待的结果:", 1000*1000)
|
||||
fmt.Println("实际结果:", counter)
|
||||
}
|
||||
24
go并发模型/06go-atomic-cpu/cpu_busy_loop.go
Normal file
24
go并发模型/06go-atomic-cpu/cpu_busy_loop.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var stop int32 = 0
|
||||
|
||||
go func() {
|
||||
for atomic.LoadInt32(&stop) == 0 {
|
||||
// 忙等:什么也不干,不让出 CPU
|
||||
}
|
||||
fmt.Println("worker 退出")
|
||||
}()
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
fmt.Println("main: 设置 stop=1")
|
||||
atomic.StoreInt32(&stop, 1)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
23
go并发模型/06go-atomic-cpu/cpu_channel_wait.go
Normal file
23
go并发模型/06go-atomic-cpu/cpu_channel_wait.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
stop := make(chan struct{})
|
||||
|
||||
go func() {
|
||||
select {
|
||||
case <-stop:
|
||||
fmt.Println("worker 收到停止信号,退出")
|
||||
}
|
||||
}()
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
fmt.Println("main: 关闭 stop channel")
|
||||
close(stop)
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
3
go并发模型/06go-atomic-cpu/go.mod
Normal file
3
go并发模型/06go-atomic-cpu/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module go-atomic-cpu
|
||||
|
||||
go 1.22.2
|
||||
81
go并发模型/07go-crawler/crawler_basic.go
Normal file
81
go并发模型/07go-crawler/crawler_basic.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
urls := []string{
|
||||
"https://golang.org",
|
||||
"https://go.dev",
|
||||
"https://www.baidu.com",
|
||||
"https://www.bing.com",
|
||||
}
|
||||
|
||||
jobs := make(chan string)
|
||||
results := make(chan string)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
workerCount := 3
|
||||
|
||||
//启动 worker
|
||||
for i := 0; i < workerCount; i++ {
|
||||
wg.Add(1)
|
||||
go worker(i, jobs, results, &wg)
|
||||
}
|
||||
|
||||
//发送任务
|
||||
go func() {
|
||||
for _, url := range urls {
|
||||
jobs <- url
|
||||
}
|
||||
close(jobs) // 关闭 channel
|
||||
}()
|
||||
|
||||
//单独goroutine 负责所有 worker结束后 关闭 results
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(results)
|
||||
}()
|
||||
|
||||
for res := range results {
|
||||
fmt.Println(res)
|
||||
}
|
||||
}
|
||||
|
||||
// worker 从 jobs 读取 URL,写结果到 results
|
||||
func worker(id int, jobs <-chan string, results chan<- string, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
for url := range jobs {
|
||||
title, err := fetchTitle(url)
|
||||
if err != nil {
|
||||
results <- fmt.Sprintf("[worker-%d] %s ERROR: %v", id, url, err)
|
||||
continue
|
||||
}
|
||||
results <- fmt.Sprintf("[worker-%d] %s => %s", id, url, title)
|
||||
}
|
||||
}
|
||||
|
||||
func fetchTitle(url string) (string, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
re := regexp.MustCompile(`<title>(.+)</title>`)
|
||||
matches := re.FindSubmatch(body)
|
||||
if len(matches) >= 2 {
|
||||
return string(matches[1]), nil
|
||||
}
|
||||
return "(no title)", nil
|
||||
}
|
||||
3
go并发模型/07go-crawler/go.mod
Normal file
3
go并发模型/07go-crawler/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module go-crawler
|
||||
|
||||
go 1.22.2
|
||||
Reference in New Issue
Block a user