• Golang sync


    Go1.9.2 sync库里包含下面几类:Mutex/RWMutex/Cond/WaitGroup/Once/Map/Pool

     

    1.Mutex:互斥锁,等同于linux下的pthread_mutex_t

    //多个线程同时运行,获得Mutex锁者线程优先执行,其余线程阻塞等待
    func testMutex() {
        mutex := sync.Mutex{};
        for i := 0; i < 10; i++ {
            go func(idx int) {
                mutex.Lock();
                defer mutex.Unlock();
                fmt.Println("idx :=", idx);
                time.Sleep(time.Second);
            }(i)
        }
    
        time.Sleep(20 * time.Second);
        fmt.Println("Func finish.");
    }

     

    2.RWMutex:读写锁,等同于linux下的pthread_rwlock_t

    //写请求在读锁和写锁时都必须阻塞等待,读请求只在写锁时阻塞等待
    func testRWMutex() {
        rwMutex := sync.RWMutex{};
        for i := 0; i < 10; i++ {
            go func(idx int) {
                rwMutex.RLock();
                defer rwMutex.RUnlock();
                fmt.Println("Read Mutex :",idx);
            }(i);
    
            go func(idx int) {
                rwMutex.Lock();
                defer rwMutex.Unlock();
                fmt.Println("Write Mutex :",idx);
                time.Sleep(time.Second);
            }(i);
        }
    
        time.Sleep(20 * time.Second);
        fmt.Println("Func finish.");
    }

     

    3.Cond:条件变量,等同于linux下的pthread_cond_t

    func testCond() {
        cond := sync.NewCond(&sync.Mutex{});
    
        cond.L.Lock(); //①上锁
        defer cond.L.Unlock();
    
        go func() {
            fmt.Println("go wait lock.");
            cond.L.Lock(); //②等Wait解锁
    
            defer cond.L.Unlock(); //⑤解锁后触发Wait
            defer fmt.Println("go unlock.");
    
            fmt.Println("go locked.");
            cond.Signal(); //④触发Wait等待解锁
        }()
    
        time.Sleep(time.Second);
    
        fmt.Println("start wait.");
        for {
            cond.Wait(); //③可以理解为立刻解锁并触发一个阻塞线程(如果没有阻塞线程则不触发)后立刻再上锁等待Signal信号
            fmt.Println("wait finish.");
            break;
        }
    
        time.Sleep(time.Second);
        fmt.Println("Func finish.");
    }

     

    4.WaitGroup:组等待

    //Add 增加等待计数;Done减少等待计数;当计数为0时触发Wait;
    func testWaitGroup() {
        waitGroup := sync.WaitGroup{};
        for i := 0; i < 10; i++ {
            waitGroup.Add(1);
    
            go func(idx int) {
                time.Sleep(time.Second);
                fmt.Println("go : ", idx);
                waitGroup.Done();
            }(i)
        }
    
        for{
            fmt.Println("start wait.");
            waitGroup.Wait();
            fmt.Println("wait finish.");
            break;
        }
    
        time.Sleep(time.Second);
        fmt.Println("Func finish.");
    }

     

    5.Once:只执行一次

    //只执行一次以后不再触发
    func testOnce() {
        once := sync.Once{};
        for i := 0; i < 10; i++ {
            go func(idx int) {
                once.Do(func() {
                    fmt.Println("Do once : ", idx); //这里只执行一次
                })
    
                fmt.Println("go : ", idx);
            }(i)
        }
    
        time.Sleep(5 * time.Second);
        fmt.Println("Func finish.");
    }

     

    6.Map:线程安全map

    func testMap() {
        syncMap := sync.Map{};
        for i := 0; i < 10; i++ {
            go func(idx int) {
                //如果没有则保存起来
                _, ok := syncMap.LoadOrStore(idx, " StrVal = "+strconv.FormatInt(int64(idx), 10));
                if !ok {
                    fmt.Println("Store idx = ",idx);
                }
            }(i)
    
            go func(idx int) {
                val, ok := syncMap.Load(idx);
                if ok {
                    fmt.Println("Load success idx = ", idx, val);
                } else {
                    fmt.Println("Load fail idx = ", idx)
                }
            }(i)
    
        }
    
        time.Sleep(5 * time.Second);
        fmt.Println("Func finish.");
    }

     

    7.Pool:线程安全对象池

    func testPool() {
        p := &sync.Pool{
            New: func() interface{} {
                return -1;
            },
        }
    
        for i := 0; i < 10; i++ {
            go func(idx int) {
                p.Put(idx);
            }(i)
        }
        
        //取出来的对象是无序的
        for i := 0; i < 20; i++ {
            go func() {
                val := p.Get();
                fmt.Println("Get val = ", val);
            }()
        }
    
        time.Sleep(5 * time.Second);
        fmt.Println("Func finish.");
    }

     使用Pool一定要注意一下问题:

    1.用途仅仅是增加对象重用的几率,减少gc的负担,而开销方面也不是很便宜的。

    2.GC会将Pool清理掉。

    3.Get不能保证将Put进去的全部取出来!如下例子:

    func testPoolPutGet(){
        myPool := &sync.Pool{
            New: func() interface{} {
                return 0;
            },
        }
    
        myPool.Put(1) //放入1
        myPool.Put(2) //放入2
    
        time.Sleep(time.Second)
    
        p1 := myPool.Get().(int)
        fmt.Println(p1) // 获得2
    
        p2 := myPool.Get().(int)
        fmt.Println(p2) // 获得0,而不是1!
    }

    4.关于Pool的实现原理,可以参考《go语言的官方包sync.Pool的实现原理和适用场景》

    以上。

  • 相关阅读:
    洛谷 P1567 统计天数【最长上升子序列/断则归一】
    洛谷 P3742 umi的函数【构造】
    洛谷 P1036 选数【背包型DFS/选or不选】
    nyoj zb的生日【背包型DFS/选or不选】
    POJ 3628 Bookshelf 2【背包型DFS/选or不选】
    【AHOI2013复仇】从一道题来看DFS及其优化的一般步骤和数组分层问题【转】
    洛谷 P1217 [USACO1.5]回文质数 Prime Palindromes【取回文数/数论/字符串】
    洛谷 P1004 方格取数 【多线程DP/四维DP/】
    Codeforces Round #449 (Div. 2) B. Chtholly's request【偶数位回文数】
    Codeforces Round #449 (Div. 2) A. Scarborough Fair【多次区间修改字符串】
  • 原文地址:https://www.cnblogs.com/chevin/p/8083022.html
Copyright © 2020-2023  润新知