diff --git a/context/context-why.go b/context/context-why.go new file mode 100644 index 0000000..8cddf4a --- /dev/null +++ b/context/context-why.go @@ -0,0 +1,43 @@ +package main + +import ( + "fmt" + "sync" + "time" +) + +var wg sync.WaitGroup + +//var notify bool + +//var exitChan chan bool = make(chan bool, 1) + +// why context + +func f() { + defer wg.Done() + //loop: + for { + fmt.Println("hello world") + time.Sleep(time.Millisecond * 500) + //if notify { + // break + //} //变量 + //select { + //case <-exitChan: + // break loop + //default: + //} //channel 版本 + } + +} + +func main() { + wg.Add(1) + go f() + time.Sleep(time.Second * 3) + //如何通知goroutine退出? + //exitChan <- true + wg.Wait() + +} diff --git a/context/context-withcancel.go b/context/context-withcancel.go new file mode 100644 index 0000000..639e097 --- /dev/null +++ b/context/context-withcancel.go @@ -0,0 +1,34 @@ +package main + +import ( + "context" + "fmt" +) + +func gen(ctx context.Context) <-chan int { + dst := make(chan int) + n := 1 + go func() { + for { + select { + case <-ctx.Done(): + return // return结束该goroutine,防止泄露 + case dst <- n: + n++ + } + } + }() + + return dst +} +func main() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() // 当我们取完需要的整数后调用cancel + + for n := range gen(ctx) { + fmt.Println(n) + if n == 5 { + break + } + } +} diff --git a/context/context-withdeadline.go b/context/context-withdeadline.go new file mode 100644 index 0000000..0cfd76f --- /dev/null +++ b/context/context-withdeadline.go @@ -0,0 +1,23 @@ +package main + +import ( + "context" + "fmt" + "time" +) + +func main() { + d := time.Now().Add(2000 * time.Millisecond) + ctx, cancel := context.WithDeadline(context.Background(), d) + + // 尽管ctx会过期,但在任何情况下调用它的cancel函数都是很好的实践。 + // 如果不这样做,可能会使上下文及其父类存活的时间超过必要的时间。 + defer cancel() + + select { + case <-time.After(1 * time.Second): + fmt.Println("overslept") + case <-ctx.Done(): + fmt.Println(ctx.Err()) + } +} diff --git a/context/context-withtimeout.go b/context/context-withtimeout.go new file mode 100644 index 0000000..5468e00 --- /dev/null +++ b/context/context-withtimeout.go @@ -0,0 +1,39 @@ +package main + +import ( + "context" + "fmt" + "sync" + + "time" +) + +// context.WithTimeout + +var Wg sync.WaitGroup + +func worker(ctx context.Context) { +LOOP: + for { + fmt.Println("db connecting ...") + time.Sleep(time.Millisecond * 10) // 假设正常连接数据库耗时10毫秒 + select { + case <-ctx.Done(): // 50毫秒后自动调用 + break LOOP + default: + } + } + fmt.Println("worker done!") + Wg.Done() +} + +func main() { + // 设置一个50毫秒的超时 + ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50) + Wg.Add(1) + go worker(ctx) + time.Sleep(time.Second * 5) + cancel() // 通知子goroutine结束 + Wg.Wait() + fmt.Println("over") +} diff --git a/context/context-withvalue.go b/context/context-withvalue.go new file mode 100644 index 0000000..bd2af78 --- /dev/null +++ b/context/context-withvalue.go @@ -0,0 +1,48 @@ +package main + +import ( + "context" + "fmt" + "sync" + + "time" +) + +// context.WithValue + +type TraceCode string + +var wait sync.WaitGroup + +func workerProc(ctx context.Context) { + key := TraceCode("TRACE_CODE") + traceCode, ok := ctx.Value(key).(string) // 在子goroutine中获取trace code + if !ok { + fmt.Println("invalid trace code") + } +LOOP: + for { + fmt.Printf("worker, trace code:%s\n", traceCode) + time.Sleep(time.Millisecond * 10) // 假设正常连接数据库耗时10毫秒 + select { + case <-ctx.Done(): // 50毫秒后自动调用 + break LOOP + default: + } + } + fmt.Println("worker done!") + wait.Done() +} + +func main() { + // 设置一个50毫秒的超时 + ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50) + // 在系统的入口中设置trace code传递给后续启动的goroutine实现日志数据聚合 + ctx = context.WithValue(ctx, TraceCode("TRACE_CODE"), "12512312234") + wait.Add(1) + go workerProc(ctx) + time.Sleep(time.Second * 5) + cancel() // 通知子goroutine结束 + wait.Wait() + fmt.Println("over") +} diff --git a/context/context.go b/context/context.go new file mode 100644 index 0000000..2f494fb --- /dev/null +++ b/context/context.go @@ -0,0 +1,52 @@ +package main + +import ( + "context" + "fmt" + "sync" + "time" +) + +var WG sync.WaitGroup + +func f1(ctx context.Context) { + defer WG.Done() + go f2(ctx) +loop: + for { + fmt.Println("hello world") + time.Sleep(time.Millisecond * 500) + select { + case <-ctx.Done(): + break loop + default: + + } + } + +} +func f2(ctx context.Context) { + defer WG.Done() +loop: + for { + fmt.Println("hello wangao") + time.Sleep(time.Millisecond * 500) + select { + case <-ctx.Done(): + break loop + default: + + } + } +} + +func main() { + ctx, cancel := context.WithCancel(context.Background()) + WG.Add(1) + go f1(ctx) + time.Sleep(time.Second * 3) + //如何通知goroutine退出? + cancel() + WG.Wait() + +} diff --git a/context/context.log b/context/context.log new file mode 100644 index 0000000..53db4b5 --- /dev/null +++ b/context/context.log @@ -0,0 +1 @@ +如何优雅的控制子goroutine退出? diff --git a/leetcode/reverseList.go b/leetcode/reverseList.go new file mode 100644 index 0000000..51a05eb --- /dev/null +++ b/leetcode/reverseList.go @@ -0,0 +1,47 @@ +package main + +import "fmt" + +type ListNode struct { + Val int + Next *ListNode +} + +func reverseList(head *ListNode) *ListNode { + var pre *ListNode + cur := head + for cur != nil { + tmp := cur.Next //暂存初始方向 + cur.Next = pre //改变链表方向 + pre = cur //移动指针 + cur = tmp //移动指针2 + } + return pre +} + +func main() { + head := &ListNode{ + Val: 1, + Next: &ListNode{ + Val: 2, + Next: &ListNode{ + Val: 3, + Next: &ListNode{ + Val: 4, + Next: &ListNode{ + Val: 5, + Next: nil, + }, + }, + }, + }, + } + fmt.Printf("%#v\n", head) + ret := reverseList(head) //反转之后的头节点 + fmt.Printf("%#v\n", ret) + for ret != nil { + fmt.Print(ret.Val, "->") + ret = ret.Next //指针移动,直到链表的尾部 + } + +}