随笔 - 38  文章 - 1  评论 - 5  阅读 - 73236

golang并发编程知识点总结

互斥锁:Mutex

复制代码
package main

import (
    "fmt"
    "sync"
)

func main() {
    var count = 0
    var mux sync.Mutex
    var wg sync.WaitGroup
    wg.Add(10)
    for i := 0; i < 10; i++ {
        go func() {
            defer wg.Done()
            for i := 0; i < 10000; i++ {
                count = count + 1
            }
            mux.Unlock()
        }()
    }
    wg.Wait()

    fmt.Printf("count=%d\n", count)
}
复制代码
复制代码
package main

import (
    "fmt"
    "sync"
    "time"
)

type Counter struct {
    mu    sync.RWMutex
    count int64
}

func (c *Counter) Incr() {
    c.mu.Lock()
    c.count = c.count + 1
    c.mu.Unlock()
}

func (c *Counter) Get() int64 {
    c.mu.RLock()
    defer c.mu.RUnlock()
    return c.count
}

func main() {
    var counter = &Counter{}
    for i := 0; i < 10; i++ { // 10个reader
        go func() {
            for {
                counter.Get() // 计数器读操作
                fmt.Printf("count=%d\n", counter.Get())
                time.Sleep(time.Millisecond)
            }
        }()
    }
    for { // 一个writer
        counter.Incr() // 计数器写操作
        time.Sleep(time.Second)
    }

}
复制代码

条件变量

复制代码
package main

import (
    "log"
    "math/rand"
    "sync"
    "time"
)

func main() {
    c := sync.NewCond(&sync.Mutex{})
    var ready int
    for i := 0; i < 10; i++ {
        go func(i int) {
            time.Sleep(time.Duration(rand.Int63n(10)) * time.Second)
            c.L.Lock()
            ready++
            c.L.Unlock()

            log.Printf("运动员#%d 已准备就绪", i)
            c.Broadcast()
        }(i)
    }
    c.L.Lock()
    for ready != 10 {
        c.Wait()
        log.Println("裁判员被唤醒一次")
    }
    c.L.Unlock()
    log.Println("所有运动员都准备就绪。比赛开始,3,2,1, ......")
}
复制代码

几种fork/join方式

复制代码
package main

import (
    "context"
    "errors"
    "fmt"
    "github.com/go-pkgz/syncs"
    "github.com/mdlayher/schedgroup"
    "github.com/vardius/gollback"
    "golang.org/x/sync/errgroup"
    "log"
    "sync/atomic"
    "time"
)

func main99() {
    var g = errgroup.Group{}

    for i := 0; i < 10; i++ {
        g.Go(func() error {
            time.Sleep(5 * time.Second)
            fmt.Println("exec #1")
            return nil
        })
    }

    if err := g.Wait(); err == nil {
        fmt.Println("Successfully exec all")
    } else {
        fmt.Println("failed:", err)
    }

}

func main98() {
    // 设置goroutine数是10
    swg := syncs.NewSizedGroup(10)
    // swg := syncs.NewSizedGroup(10, syncs.Preemptive)
    var c uint32

    // 执行1000个子任务,只会有10个goroutine去执行
    for i := 0; i < 1000; i++ {
        swg.Go(func(ctx context.Context) {
            time.Sleep(5 * time.Millisecond)
            atomic.AddUint32(&c, 1)
        })
    }

    // 等待任务完成
    swg.Wait()
    // 输出结果
    fmt.Println(c)
}

func main97() {
    rs, errs := gollback.All( // 调用All方法
        context.Background(),
        func(ctx context.Context) (interface{}, error) {
            time.Sleep(3 * time.Second)
            return 1, nil // 第一个任务没有错误,返回1
        },
        func(ctx context.Context) (interface{}, error) {
            return nil, errors.New("failed") // 第二个任务返回一个错误
        },
        func(ctx context.Context) (interface{}, error) {
            return 3, nil // 第三个任务没有错误,返回3
        },
    )

    fmt.Println(rs)   // 输出子任务的结果
    fmt.Println(errs) // 输出子任务的错误信息

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    res, err := gollback.Retry(ctx, 5, func(ctx context.Context) (interface{}, error) {
        log.Print("重试...")
        return nil, errors.New("failed")
    })
    fmt.Println(res) // 输出结果
    fmt.Println(err) // 输出错误信息
}

func main() {
    sg := schedgroup.New(context.Background())

    // 设置子任务分别在100、200、300之后执行
    for i := 0; i < 3; i++ {
        n := i + 1
        sg.Delay(time.Duration(n)*100*time.Millisecond, func() {
            log.Println(n) //输出任务编号
        })
    }

    // 等待所有的子任务都完成
    if err := sg.Wait(); err != nil {
        log.Fatalf("failed to wait: %v", err)
    }
}
复制代码

信号量:Seamphore

复制代码
package main

import (
    "context"
    "fmt"
    "golang.org/x/sync/semaphore"
    "log"
    "runtime"
    "time"
)

var (
    maxWorkers = runtime.GOMAXPROCS(0)                    // worker数量
    sema       = semaphore.NewWeighted(int64(maxWorkers)) //信号量
    task       = make([]int, maxWorkers*4)                // 任务数,是worker的四倍
)

func main() {
    log.Printf("max workers:%d", maxWorkers)

    ctx := context.Background()
    max := len(task) * 2
    for i := 0; i < max; i++ {
        // 如果没有worker可用,会阻塞在这里,直到某个worker被释放
        if err := sema.Acquire(ctx, 1); err != nil {
            log.Printf("发生阻塞...")
            break
        }

        // 启动worker goroutine
        go func(i int) {
            defer sema.Release(1)
            time.Sleep(1000 * time.Millisecond) // 模拟一个耗时操作
            task[i] = i + 1
            fmt.Println("执行。。。")
        }(i)
    }

    // 请求所有的worker,这样能确保前面的worker都执行完
    if err := sema.Acquire(ctx, int64(maxWorkers)); err != nil {
        log.Printf("获取所有的worker失败: %v", err)
    }

    fmt.Println(task)
}
复制代码

 

posted on   王冬冬冬不烦恼  阅读(47)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示