V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
iwdmb
V2EX  ›  问与答

利用循环确保队列有东西的情况才取值,导致 CPU 100% 占用

  •  
  •   iwdmb · 2020-04-17 01:00:21 +08:00 · 1955 次点击
    这是一个创建于 1710 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大家好,目前遇到了一个问题,苦思許久没有比较好的解法。

    我有一个队列,想要确保其里面有东西的情况,才将其取出并删除,必须要是线程安全的。

    while (true) {
    	if deque.length() > 0 {
    		// deque.popBack
    	}
        
        // sleep
    }
    

    这段代码在 deque.length() 一直为 0 的时候,会导致 CPU 占用 100%。

    想询问除了加上 sleep 有没有比较好的作法。

    谢谢大家!

    P.s. 在 Golang 可以透过 Channel 解决这个问题,不过 Channel 本身涉及到了 runtime 的调度,想知道在其他语言 例如 Java or C++ 是如何解决这个问题的。

    17 条回复    2020-04-17 10:48:06 +08:00
    araaaa
        1
    araaaa  
       2020-04-17 01:21:20 +08:00 via iPhone
    用单线程池做定时任务
    iwdmb
        2
    iwdmb  
    OP
       2020-04-17 01:25:18 +08:00
    @araaaa
    可能是我描述的不清楚
    我主要是想解决在没有延迟的情况处理 deque 中的资料
    同时避免 CPU 100% 的问题
    iwdmb
        3
    iwdmb  
    OP
       2020-04-17 01:26:14 +08:00
    sleep 只是其中一个解法,可是我希望可以做到不要延迟的处理 deque
    litmxs
        4
    litmxs  
       2020-04-17 01:28:26 +08:00 via Android
    入队的时候唤醒线程?
    araaaa
        5
    araaaa  
       2020-04-17 01:29:43 +08:00 via iPhone
    @iwdmb #2 调度周期间隔可以定位毫秒或者微秒
    luckyrayyy
        6
    luckyrayyy  
       2020-04-17 01:33:19 +08:00 via iPhone
    Java 里面有很多现成的实现,队里为空的时候线程就阻塞了。
    iwdmb
        7
    iwdmb  
    OP
       2020-04-17 01:34:12 +08:00
    @litmxs 與 Golang Channel 的原理其實很相似了。
    gaobing
        8
    gaobing  
       2020-04-17 01:35:31 +08:00 via Android   ❤️ 1
    生产者消费者是任何语言的并发或者多线程编程的入门例子吧。。。看你写的像 Java,Java 里面 wait notify 配套,await signal 配套,或者 BlockingQueue 都可以。
    iwdmb
        9
    iwdmb  
    OP
       2020-04-17 01:35:57 +08:00
    @luckyrayyy 看起来思路都是类似的,不知道能不能请前辈推荐 Java 开源项目有類似的實現,感谢。
    或是有什么关键字之类的。
    iwdmb
        10
    iwdmb  
    OP
       2020-04-17 01:37:20 +08:00
    @gaobing 看起来就是 BlockingQueue,实在是见识浅薄,真的非常感谢。
    luckyrayyy
        11
    luckyrayyy  
       2020-04-17 01:40:26 +08:00 via iPhone   ❤️ 1
    @iwdmb TransferQueue,LinkedBlockingQuque,ArrayBlockingQueue 。
    iwdmb
        12
    iwdmb  
    OP
       2020-04-17 01:47:18 +08:00
    @gaobing @luckyrayyy 多谢两位前辈,原来是生产者消费者唤醒问题这么基础大学就学过的案例,回头要再去复习一下恐龙书。
    crella
        13
    crella  
       2020-04-17 01:47:19 +08:00 via Android
    不如定义一个 Deque 类,它的实例变量 data 和 waitlist 是两个数组,类有 add()和 out_call()方法。

    外部通过 Deque.add(obj)方法来给 deque 队列添加元素,也就是添加到 data 数组里。然后 add()方法快结束时给 waitlist 添加所有在 data 里的对象,然后新建线程执行 out_call()方法。

    out_call()方法执行时,新建数组 currentlist=waitlist 深拷贝,然后逐个对应删除 waitlist 内的对象,然后遍历本函数内的 currentlist 执行外部函数操作即可。

    我不会协程,只会简单的多线程操作。上面涉及到 data 和 waitlist 的注意加好互斥锁。


    其实说简陋点,像 windows 窗口,点击一下按钮就有反应,实际上是 window UI 线程在主循环,而不是外部函数在循环检查 win UI 线程。把 Deque 类当作 win UI 线程应该可以。实际上听说 winform 程序都是把 UI 当做主线程的。再说得简单点就是把 Deque 类当成数组并给它加一个“点击按钮”后的操作,这里的“点击按钮”应该就是多线程往数组添加吧。

    我之前想给 ruby 的 Array 也添加一个操作,让它被添加元素后自动执行操作。后来想一下还是用类似上面的 Deque 类包装一个类型为 Array 的实例变量好了。


    以上都未经验证,纯属猜想。
    hsyu53
        14
    hsyu53  
       2020-04-17 01:50:14 +08:00
    c++的话,可以用 mutex + condition variable
    Mithril
        15
    Mithril  
       2020-04-17 02:02:15 +08:00
    直接用 ReactiveX 就好了,响应式的思路明显更简单。
    虽说实际上也是开了线程处理吧。
    dicc
        16
    dicc  
       2020-04-17 10:47:03 +08:00
    为啥不直接 Queue.get()呢
    默认就是 block 永不超时
    dicc
        17
    dicc  
       2020-04-17 10:48:06 +08:00
    哦,你这不是 python..
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2718 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 11:29 · PVG 19:29 · LAX 03:29 · JFK 06:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.