372 lines
6.0 KiB
Go
372 lines
6.0 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
// 5.1 Goroutine 基础
|
|
func say(s string) {
|
|
for i := 0; i < 3; i++ {
|
|
time.Sleep(100 * time.Millisecond)
|
|
fmt.Println(s)
|
|
}
|
|
}
|
|
|
|
func goroutineBasic() {
|
|
fmt.Println("=== Goroutine 基础 ===")
|
|
go say("world")
|
|
say("hello")
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
|
|
// 5.2 GMP 模型演示
|
|
func gmpDemo() {
|
|
fmt.Println("\n=== GMP 模型 ===")
|
|
fmt.Printf("GOMAXPROCS: %d\n", runtime.GOMAXPROCS(0))
|
|
fmt.Printf("NumCPU: %d\n", runtime.NumCPU())
|
|
fmt.Printf("NumGoroutine: %d\n", runtime.NumGoroutine())
|
|
}
|
|
|
|
// 5.3 Channel 基础
|
|
func channelBasic() {
|
|
fmt.Println("\n=== Channel 基础 ===")
|
|
|
|
// 无缓冲 Channel
|
|
ch := make(chan int)
|
|
go func() {
|
|
ch <- 42
|
|
}()
|
|
val := <-ch
|
|
fmt.Println("无缓冲 Channel:", val)
|
|
|
|
// 有缓冲 Channel
|
|
bufferedCh := make(chan int, 2)
|
|
bufferedCh <- 1
|
|
bufferedCh <- 2
|
|
fmt.Println("有缓冲 Channel:", <-bufferedCh, <-bufferedCh)
|
|
}
|
|
|
|
// 5.3 Channel 关闭与遍历
|
|
func channelClose() {
|
|
fmt.Println("\n=== Channel 关闭与遍历 ===")
|
|
ch := make(chan int)
|
|
|
|
go func() {
|
|
for i := 0; i < 5; i++ {
|
|
ch <- i
|
|
}
|
|
close(ch)
|
|
}()
|
|
|
|
for val := range ch {
|
|
fmt.Print(val, " ")
|
|
}
|
|
fmt.Println()
|
|
|
|
// 检查关闭
|
|
if _, ok := <-ch; !ok {
|
|
fmt.Println("Channel 已关闭")
|
|
}
|
|
}
|
|
|
|
// 5.3 工作池
|
|
func worker(id int, jobs <-chan int, results chan<- int) {
|
|
for j := range jobs {
|
|
fmt.Printf("Worker %d 处理 %d\n", id, j)
|
|
time.Sleep(100 * time.Millisecond)
|
|
results <- j * 2
|
|
}
|
|
}
|
|
|
|
func workerPoolDemo() {
|
|
fmt.Println("\n=== 工作池 ===")
|
|
jobs := make(chan int, 10)
|
|
results := make(chan int, 10)
|
|
|
|
for w := 1; w <= 3; w++ {
|
|
go worker(w, jobs, results)
|
|
}
|
|
|
|
for j := 1; j <= 5; j++ {
|
|
jobs <- j
|
|
}
|
|
close(jobs)
|
|
|
|
for r := 1; r <= 5; r++ {
|
|
<-results
|
|
}
|
|
fmt.Println("工作池完成")
|
|
}
|
|
|
|
// 5.3 Select
|
|
func selectDemo() {
|
|
fmt.Println("\n=== Select ===")
|
|
ch1 := make(chan string)
|
|
ch2 := make(chan string)
|
|
|
|
go func() {
|
|
time.Sleep(500 * time.Millisecond)
|
|
ch1 <- "来自 ch1"
|
|
}()
|
|
|
|
go func() {
|
|
time.Sleep(300 * time.Millisecond)
|
|
ch2 <- "来自 ch2"
|
|
}()
|
|
|
|
for i := 0; i < 2; i++ {
|
|
select {
|
|
case msg1 := <-ch1:
|
|
fmt.Println(msg1)
|
|
case msg2 := <-ch2:
|
|
fmt.Println(msg2)
|
|
case <-time.After(1 * time.Second):
|
|
fmt.Println("超时")
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// 5.4 WaitGroup
|
|
func waitGroupDemo() {
|
|
fmt.Println("\n=== WaitGroup ===")
|
|
var wg sync.WaitGroup
|
|
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func(id int) {
|
|
defer wg.Done()
|
|
fmt.Printf("Worker %d 开始\n", id)
|
|
time.Sleep(200 * time.Millisecond)
|
|
fmt.Printf("Worker %d 完成\n", id)
|
|
}(i)
|
|
}
|
|
|
|
wg.Wait()
|
|
fmt.Println("所有任务完成")
|
|
}
|
|
|
|
// 5.4 Mutex
|
|
func mutexDemo() {
|
|
fmt.Println("\n=== Mutex ===")
|
|
var mu sync.Mutex
|
|
var count int
|
|
|
|
for i := 0; i < 1000; i++ {
|
|
go func() {
|
|
mu.Lock()
|
|
count++
|
|
mu.Unlock()
|
|
}()
|
|
}
|
|
|
|
time.Sleep(1 * time.Second)
|
|
fmt.Println("Count:", count)
|
|
}
|
|
|
|
// 5.4 RWMutex
|
|
func rwMutexDemo() {
|
|
fmt.Println("\n=== RWMutex ===")
|
|
var mu sync.RWMutex
|
|
var data = make(map[string]int)
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
// 读操作
|
|
for i := 0; i < 10; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
mu.RLock()
|
|
_ = data["key"]
|
|
mu.RUnlock()
|
|
}()
|
|
}
|
|
|
|
// 写操作
|
|
for i := 0; i < 5; i++ {
|
|
wg.Add(1)
|
|
go func() {
|
|
defer wg.Done()
|
|
mu.Lock()
|
|
data["key"]++
|
|
mu.Unlock()
|
|
}()
|
|
}
|
|
|
|
wg.Wait()
|
|
fmt.Println("Data:", data)
|
|
}
|
|
|
|
// 5.4 Once
|
|
func onceDemo() {
|
|
fmt.Println("\n=== Once ===")
|
|
var once sync.Once
|
|
setup := func() {
|
|
fmt.Println("初始化一次")
|
|
}
|
|
|
|
for i := 0; i < 5; i++ {
|
|
go func() {
|
|
once.Do(setup)
|
|
}()
|
|
}
|
|
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
|
|
// 5.5 Atomic
|
|
func atomicDemo() {
|
|
fmt.Println("\n=== Atomic ===")
|
|
var count int64
|
|
|
|
for i := 0; i < 1000; i++ {
|
|
go func() {
|
|
atomic.AddInt64(&count, 1)
|
|
}()
|
|
}
|
|
|
|
time.Sleep(1 * time.Second)
|
|
fmt.Println("Atomic Count:", atomic.LoadInt64(&count))
|
|
}
|
|
|
|
// 5.6 Context
|
|
func contextDemo() {
|
|
fmt.Println("\n=== Context ===")
|
|
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
|
|
defer cancel()
|
|
|
|
go func() {
|
|
select {
|
|
case <-time.After(1 * time.Second):
|
|
fmt.Println("任务完成")
|
|
case <-ctx.Done():
|
|
fmt.Println("任务取消:", ctx.Err())
|
|
}
|
|
}()
|
|
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
|
|
// 5.8 管道
|
|
func pipelineDemo() {
|
|
fmt.Println("\n=== 管道 ===")
|
|
|
|
// 生成
|
|
gen := func(nums ...int) <-chan int {
|
|
out := make(chan int)
|
|
go func() {
|
|
for _, n := range nums {
|
|
out <- n
|
|
}
|
|
close(out)
|
|
}()
|
|
return out
|
|
}
|
|
|
|
// 平方
|
|
sq := func(in <-chan int) <-chan int {
|
|
out := make(chan int)
|
|
go func() {
|
|
for n := range in {
|
|
out <- n * n
|
|
}
|
|
close(out)
|
|
}()
|
|
return out
|
|
}
|
|
|
|
c := gen(1, 2, 3)
|
|
c = sq(c)
|
|
|
|
for n := range c {
|
|
fmt.Println(n)
|
|
}
|
|
}
|
|
|
|
// 5.9 并发爬虫
|
|
type Crawler struct {
|
|
visited map[string]bool
|
|
mu sync.Mutex
|
|
wg sync.WaitGroup
|
|
limit chan struct{}
|
|
}
|
|
|
|
func (c *Crawler) crawl(url string, depth int) {
|
|
if depth <= 0 {
|
|
return
|
|
}
|
|
|
|
c.limit <- struct{}{}
|
|
defer func() { <-c.limit }()
|
|
defer c.wg.Done()
|
|
|
|
c.mu.Lock()
|
|
if c.visited[url] {
|
|
c.mu.Unlock()
|
|
return
|
|
}
|
|
c.visited[url] = true
|
|
c.mu.Unlock()
|
|
|
|
fmt.Println("抓取:", url)
|
|
|
|
// 模拟子链接
|
|
links := []string{url + "/1", url + "/2"}
|
|
for _, link := range links {
|
|
c.wg.Add(1)
|
|
go c.crawl(link, depth-1)
|
|
}
|
|
}
|
|
|
|
func crawlerDemo() {
|
|
fmt.Println("\n=== 并发爬虫 ===")
|
|
crawler := &Crawler{
|
|
visited: make(map[string]bool),
|
|
limit: make(chan struct{}, 5),
|
|
}
|
|
|
|
crawler.wg.Add(1)
|
|
go crawler.crawl("http://example.com", 2)
|
|
|
|
crawler.wg.Wait()
|
|
fmt.Println("爬虫完成")
|
|
}
|
|
|
|
// 5.10 竞态检测示例(需配合 -race 运行)
|
|
func raceDemo() {
|
|
fmt.Println("\n=== 竞态检测示例 ===")
|
|
var count int
|
|
|
|
for i := 0; i < 100; i++ {
|
|
go func() {
|
|
count++ // 竞态!
|
|
}()
|
|
}
|
|
|
|
time.Sleep(1 * time.Second)
|
|
fmt.Println("Count:", count)
|
|
}
|
|
|
|
func main() {
|
|
goroutineBasic()
|
|
gmpDemo()
|
|
channelBasic()
|
|
channelClose()
|
|
workerPoolDemo()
|
|
selectDemo()
|
|
waitGroupDemo()
|
|
mutexDemo()
|
|
rwMutexDemo()
|
|
onceDemo()
|
|
atomicDemo()
|
|
contextDemo()
|
|
pipelineDemo()
|
|
crawlerDemo()
|
|
raceDemo()
|
|
}
|