zoukankan      html  css  js  c++  java
  • go条件变量的使用和原理

    场景

    最近写代码时碰到一个场景, 需要使用 map[int]struct{} 结构来存储task, map的key是task的id,随时可以增减。因为的确除了看书,基本上没使用过条件变量所以后面过了一天才想到可以用条件变量来实现。记得在某篇博客上看到的一句话挺不错,大概是同步语句中,条件变量的特点在于等待。

    一开始代码大概是这样的

    事件循环

    func Loop() {
    	for {
        	mutex.Lock()
    		for taskId, task := range tasks {
        		// handle code
    		}
        	lenght := len(task)
        	mutex.UnLock()
    
    		// 为了减少cpu空转  当队列为空的时候sleep 2秒
            if length == 2 {
        		time.Sleep(time.Secord * 2)
            }
        }
    }   
    

    新增task(删除也是类似)

    func addTask(t *Task) {
        mutex.Lock()
        tasks[t.Id] = t
        mutex.UnLock()
    }
    

    使用条件变量

    使用条件变量之后的事件循环代码

    func Loop() {
        for {
            mutex.Lock()
            // 如果当前任务数为0 调用Wait()等待新任务增加时唤醒
            if len(tasks) == 0 {
                cond.Wait() // cond := sync.NewCond(&mutex)
            }
    
    		for taskId, task := range tasks {
        		// handle code
    		}
            mutex.UnLock()
        }
    }
    

    新增task(删除task代码不作改变)

    func addTask(t *Task) {
        mutex.Lock()
        tasks[t.Id] = t
        if len(task) == 1 {  // 从0->1 可能之前有goruntine阻塞
        	cond.Signal()    // 由于Loop()是单协程在跑所以 使用的是Signal()足矣
        }
        mutex.UnLock()
    }
    

    条件变量原理(和语言无关)

    如果是C语言的pthread_cond条件变量和GO最主要的区别,本质上还是协程和真正的内核线程的区别, go 自带sync包里的条件变量 对goruntine的操作,其阻塞/唤醒不需要陷入内核态。

    Wait()

    func (c *Cond) Wait() {
        c.checker.check()
        t := runtime_notifyListAdd(&c.notify)  // 等待的goruntine数+1
        c.L.Unlock() // 释放锁资源
        runtime_notifyListWait(&c.notify, t) // 阻塞,等待其他goruntine唤醒
        c.L.Lock() // 获取资源
    }
    

    Signa() 和 BroadCast()

    func (c *Cond) Signal() {
        c.checker.check()
        runtime_notifyListNotifyOne(&c.notify) // 唤醒最早被阻塞的goruntine
    }
    
    func (c *Cond) Broadcast() {
        c.checker.check()
        runtime_notifyListNotifyAll(&c.notify) // 唤醒所有goruntine
    }
    
  • 相关阅读:
    统一回复《怎么学JavaScript?》
    nodejs配置简单HTTP服务器
    web跨域解决方案
    JavaScript 调试小技巧
    我从编程总结的 22 个经验
    Sublime Text 3103 Crack 破解 注册码(亲测有效)
    mstsc 远程序桌面登录的 c#开发
    突然顿悟的Javascript中的this
    解决Electron加载带jquery的项目报错问题
    ES6+ 开发 React 组件
  • 原文地址:https://www.cnblogs.com/Me1onRind/p/11653561.html
Copyright © 2011-2022 走看看