Why must I "sleep" in an infinite for-loop to keep CPU usage at bay?

blov · · 684 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I wrote a program where the main kicks off a goroutine that loops infinitely and based on elapsed time, reacts in some way. Within each loop I&#39;m making this elapsed time check.</p> <p>The rest of the main blocks on user input to interact with the state that the goroutine depends on.</p> <p>Everything seemed to work fine but then I noticed that the CPU was maxed out from my program. A simple <code>Sleep</code>at the end of the infinite loop got in back on track.</p> <p>Why is this? Is Sleep even the proper solution here?</p> <hr/>**评论:**<br/><br/>akavel: <pre><p>That&#39;s how computers work: if you order a CPU to run in circles (loop), it will obediently fulfill your request! A Sleep is better than nothing, but a preferable solution could be potentially to insert a select instead, and signal the trigger event via a channel to the select. Hard to suggest something more concrete without seeing related fragments of your code. By the way, have you tested your code with race detector enabled?</p></pre>shovelpost: <pre><blockquote> <p>If a program is too slow, it must have a loop.</p> <p>-Ken Thompson</p> </blockquote></pre>levenfyfe: <pre><p>Are you using a Ticker (<a href="https://gobyexample.com/tickers" rel="nofollow">https://gobyexample.com/tickers</a> ) or literally an infinite loop that checks elapsed time every iteration? The latter will definitely burn a lot of CPU, as it&#39;s processing that loop as fast as it can, checking the elapsed time as often as possible.</p> <p>With a ticker, the goroutine will be idle between the end of one loop and the next tick.</p></pre>-proof: <pre><p>I was using an infinite loop that checked elapsed time every iteration.</p> <p>For some reason I didn&#39;t like the idea of relying on a ticker since the tick period could change over time, and sometimes a given period would only really execute once.</p></pre>faiface: <pre><p>A ticker is (I assume) using the CPU&#39;s time interruptions, so it&#39;s definitely much more precise than anything you can possibly do with a loop.</p></pre>littlehawk93: <pre><p>Your gorountine is calculating the time difference with as many free clock cycles as the CPU has for it, which is why it uses so much CPU resources. Adding the sleep reduces the load because the gorountine rests but it&#39;s still just running the CPU over and over until the time has elapsed</p></pre>-proof: <pre><p>Is that valid or misleadingly heavy?</p></pre>littlehawk93: <pre><p>I don&#39;t understand what you&#39;re asking. I&#39;m not misleading you (at least not intentionally). You made a loop that basically subtracts two numbers (two timestamps) to determine how much time has elapsed. If you don&#39;t put a delay (sleep) in that loop, the CPU is going to subtract those timestamps as fast as it possibly can.</p> <p>Adding a sleep will reduce CPU load, but still potentially make the program unresponsive. The CPU won&#39;t be flooded with calculations, but the gorountine won&#39;t respond to your input until after it has &#34;woken up&#34; from it&#39;s sleep </p></pre>-proof: <pre><p>Right what I mean if you have many processes that have an infinite loop with short sleep periods, then surely it accumulates and slows down the cpu quicker overall?</p> <p>I can’t think of any other way to do it. A millisecond delay doesn’t sound too bad</p></pre>tdewolff: <pre><p>What&#39;s wrong with a CPU at 100%? You want a fast loop, so that&#39;s what it&#39;s giving you. Do you need it to <code>sleep</code> for the GC to run or for the goroutine scheduler to run? Or is that goroutine eating up the entire CPU power?</p> <p>Adding a <code>sleep</code> every iteration is a classic way to solve this, but this sounds like something <code>Ticker</code> was designed for to fix.</p></pre>justinisrael: <pre><p>If you know the actions you want to perform at various intervals, create a goroutine that selects from one or more tickers (<a href="https://golang.org/pkg/time/#Tick" rel="nofollow">https://golang.org/pkg/time/#Tick</a>). Each ticker case will unblock at the correct interval. If you say that the intervals constantly change over time, you can also dynamically select from a list of N channels using reflection: <a href="https://stackoverflow.com/a/19992525/496445" rel="nofollow">https://stackoverflow.com/a/19992525/496445</a></p> <p>Otherwise if you are set on a sleep, you can have one goroutine for each interval action and you can adjust the sleep interval after each loop. </p></pre>-proof: <pre><p>You&#39;re saying sleep for the tick period? like sleep for 25 mins rather than sleep for a millisecond and keep checking?</p></pre>justinisrael: <pre><p>If you want to perform an action in 25 minutes, why would you keep checking a time difference to see if it has been 25 minutes when you could use a ticker for 25 min? You can even have the ability to cancel the tick if you select over the ticker and a cancellation </p></pre>-proof: <pre><p>Is it more efficient or really the same under the hood? Will look into using a ticker on a more serious project.</p></pre>elastic_psychiatrist: <pre><p>It is <em>considerably</em> more efficient to use a ticker. </p></pre>justinisrael: <pre><p>Looping ever millisecond to check a time value is way more cpu intensive than letting the Go scheduler wake up your select when the actual target interval is reached. </p></pre>-proof: <pre><p>How is the scheduler efficient itself then? Because what you&#39;re saying sounds like magic to me :o</p></pre>justinisrael: <pre><p>The Go runtime has a more efficient way to handle timers: <a href="https://golang.org/src/runtime/time.go" rel="nofollow">https://golang.org/src/runtime/time.go</a></p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

684 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传