-
Notifications
You must be signed in to change notification settings - Fork 17.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
runtime: tight loop hangs process completely after some time #15442
Comments
I can not recreate the problem on GNU/Linux (using the |
It's not Windows-specific. The same thing happens on OS X. Just tested both versions on Ubuntu 14.04 LTS 3.13.0-24-generic virtual machine with Go 1.6.2 64-bit. Both versions hang after 20 seconds. Adding |
I just ran the program using When the program hangs on GNU/Linux, kill it by typing |
Another interesting find. I was running the program through ssh and it caused program to output more slowly. And process was no longer hanging. Once I ran it in VM terminal itself it did hang. Tried to output to a file instead of the console to remove the bottleneck - hangs within a second. So it looks like execution speed affects this issue. Source
Linux backtrace
OS X backtrace
|
I can confirm the behaviour on 14.04 on a KVM with 3 VPUs. go is 1.6.0 This is the scheduler as the programm begins to spin. 2016/04/27 05:48:11 received On 26 April 2016 at 22:38, Antonenko Artem notifications@github.com wrote:
|
@creker I'm sorry but we cannot accept a bug with a The reason this program stalls is the I am going to close this issue as I do not believe there is an issue. I recommend if you want to discuss this further please take this to another forum, such as the mailing list. |
@davecheney it looks from my skimming of the issue that it also reproduces with |
@josharian i think there is still a
If this issue can be reproduced without a |
Hmm. The original report doesn't match the later one. Those who can reproduce this: Does it reproduce without any for {} loops? |
Using an empty select has other side effects. Being very old and just a import ( func main() {
is", i)
} On 27 April 2016 at 06:33, Josh Bleecher Snyder notifications@github.com
|
What other side effects ? |
On 27 April 2016 at 07:14, Dave Cheney notifications@github.com wrote:
rgds, Nigel Vickers
|
I'm sorry this seems unrelated to the original issue. The reason for using If you believe there is a bug, can you please produce a runnable sample that does not use a |
I confirm that the behaviour experienced using for{} in main() in the test On 27 April 2016 at 08:35, Dave Cheney notifications@github.com wrote:
|
Thank you, that does explain why this is happening. If I insert It still look like a strange behaviour to lock entire process but at least I understand why it's happening. Hope that #10958 would be fixed as it does look like it may affect real production code. |
@rhedile A literal |
I'm starting to think that if the compiler sees an (obviously) infinite loop, it could arrange to insert a call to select{} |
I think inserting a call to runtime.Gosched() in (obvious) infinite loops
might be more appropriate (it changes the code semantics less, select {}
breaks the code whereas the programmer obviously want to loop)
At least most of similar reports on the issue tracer involves for {}, so
if the compiler could insert call to runtime.Gosched() automatically,
it should help with those reports.
However, people might intentionally use for {} to keep one goroutine
busy, so I'm not sure we need to do something here.
|
Maybe instead compiler should generate an error if he encounters an infinite loop? Now program just locks up without any diagnostic messages and to understand why you need to understand how goroutines are scheduled. And in case of this issue even that didn't help me, I didn't know that GC could also do that. for {} is not usuable for anything, it's just generates the issue. Even if for {} has a body compiler probably can detect that it will never call the runtime. For example, if every function call (which also doesn't call the runtime) is inlined then scheduler will not be called on function entry. But I suspect it will require much more complex analysis. On the other hand, if loop body has anything useful then it's no longer an issue because it will eventually call the runtime. |
Then there would be no way to write a CPU baking program. On a more serious note, empty for loop is a legal language concept, sending SIGQUIT diagnoses it easily if needed. |
Well, it didn't help me. SIGQUIT didn't output anything that would tell me that it's GC that locked up the process. The stacktrace doesn't even mention any relevant Go runtime sources so that I could at least start somewhere. Yes, for {} loop is legal but it leads to program that locks up without telling why. You have to understand Go runtime to know why and not even the basics of it. There're 3 solutions that I can think of right now:
|
If SIGQUIT doesn't show the for {} loop line, it's probably worth filing an issue. Meanwhile, grep 'for {}' to the rescue. Most programs should not have that line, ever. |
It does show it but it doesn't tell the reason. for {} is not the reason, it's how GC works is what causes the issue. for {} just triggers it. The whole point here is to understand why. I agree and as I said, for {} is useless in real code. What I forgot to mention is it's not me who found that issue http://stackoverflow.com/questions/36826622/why-is-the-following-code-sample-stuck-after-some-iterations/ I couldn't understand why it behaves like it does, started playing with it and decided to open the issue to help me and everyone else understand what's going on. It's an edge case when people learning Go. And most of the time they are about goroutines scheduling. For example, you insert for {} and suddenly your goroutines are no longer scheduled because GOMAXPROCS=1 and scheduler is never given a chance to execute any other goroutine. People still have difficulties with that but at least SO has many great answers that cover exactly why it works like that. There're blog posts that cover the scheduler and from that it's obvious why. But the issue here is not covered anywhere. Which leads to a bigger problem - the lack of good diagnostic messages when process locks up and people don't understand why. Yes, it's useless non-production code but it's very important when you're learning new stuff. You're playing with it, deliberately triggering edge cases to understand the limitations. And it's good when program tells you that you reached the limit. Right now your program just hangs. To understand why you either need to ask another question on SO which will be closed as duplicate or left unanswered or you google anything on Go runtime, read blog posts, Go team mail lists and Google Docs. Here it didn't help me. No one gave an answer to that SO question, accepted answer is wrong. And it's not like there isn't anyone who understands Go well - many answers are from Google employees themselves. So it would be great to either print somehow a diagnostic message which might be not very easy in these cases. Or insert runtime.Gosched() and solve these issues once and for all. Right now it's like C++ - something is broken but only a few chosen ones understand why. For me, that's not what Go is about. Sorry for such a long comment. |
The GC needs to preempt a goroutine in a timely fashion. Preemption happens There are a couple of ways to avoid this issue, one is to accept the fact At the end of the day it is a matter of where the community wants to put On Sun, May 1, 2016 at 10:25 AM, Antonenko Artem notifications@github.com
|
I just don't think we need to solve the problem.
Tight loops are created for a reason, and the
compiler should respect that.
for {} is troublesome, but most of them are used
in toy examples.
|
I agree. I don't think this is a problem that needs to be solved in code. On Wed, May 4, 2016 at 8:14 AM, Minux Ma notifications@github.com wrote:
|
Please answer these questions before submitting your issue. Thanks!
go version
)?go version go1.6.2 windows/amd64
go env
)?Windows 10.0.10586 am64
Ran this code
Process printing "sent" and "received" until terminated
Process runs and prints as expected for about 2 seconds and then hangs. Nothing is printed after that, process just eats up CPU. No panics or anything.
I put
runtime.GOMAXPROCS(2)
to make sure that there're multiple threads that goroutines can ran on. Obviously withruntime.GOMAXPROCS(1)
process would hang immediately as expected - for loop will not yield execution.I tried to replace the for loop with this so that main goroutine can yield execution:
But exactly the same thing happens. Now, if I put
time.Sleep(10 * time.Millisecond)
or longer afterlog.Println("sent")
then process no longer hangs. I ran it for a minute and it's just kept going. Don't know, maybe it will still hang much later. If I change it to 2 ms then it hangs after 30 seconds. I tried to collect trace data but it looks like it gets corrupted because trace doesn't finish. When I try to view the trace it says "failed to parse trace: no EvFrequency event".Everything behaves exactly the same on Mac OSX El capitan 10.11.4 (15E65) Go 1.6.2
I read the #10958 but here the weird thing is that it actually runs for awhile completely fine and only after that it hangs.
The text was updated successfully, but these errors were encountered: