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
syscall: fork blocks the process #5717
Labels
Milestone
Comments
This is related to https://golang.org/issue/5517 Fork takes 15-20ms and it completely blocks process. |
>> The problem is with fork() call with 2.2GB heap size. It takes >> ~10-20ms and is called with RawSyscall, so nothing can happen >> meanwhile. I was planning on doing something similar with a server I'm writing, where I would periodically make calls to uptime(1) to get ahold of the load average. Dmitry notes that "things are not that bad with GOMAXPROCS>1, fork block only 1 thread. " |
one alternative is to fix issue #5838. |
changed to syscall it is not about memory usage the problem is that fork call is "nonblocking" from the point of view of runtime, so it does not schedule other goroutines during fork. In reality fork can take 20+ms, and I suspect be mostly blocking (swap or something). if we just make it a normal syscall, it will hang in child (runtime mutexes can be locked). however if we skip exitsyscall in child it should do the trick. |
Simpler reproducer: package main import ( "fmt" "os/exec" "time" ) //var ballast = make([][]byte, 2e8) func main() { go func() { prev := time.Now() for now := range time.NewTicker(time.Millisecond).C { fmt.Println(now.Sub(prev)) prev = now } }() for { exec.Command("ls").CombinedOutput() } } With the ballast there are that 15ms delays: 999.337us 996.273us 1.001548ms 1.003009ms 1.000131ms 1.022096ms 15.632691ms 321.769us 995.469us 999.496us 1.000067ms 999.972us 1.000004ms 1.000169ms 999.43us 16.426056ms 583.624us 990.718us 1.012777ms 987.411us 999.783us 999.792us 1.000195ms 999.824us 15.317368ms 687.186us 995.589us 999.954us |
The problem is that fork on linux uses RawSyscall, so it completely blocks the process. One solution may be to carefully use vfork, it should be much faster. Another solution may be to carefully use entersyscall/exitsyscall around fork, but the child process must not execute exitsyscall because it can deadlock. |
Unfortunately it's not a problem with Go runtime. Even if I call entersyscallblock/exitsyscall around fork, OS blocks syscalls in other threads for the duration of fork: [pid 29109] 23:18:19.586480 fork( <unfinished ...> [pid 29114] 23:18:19.586490 <... futex resumed> ) = 0 <0.001167> [pid 29113] 23:18:19.586500 <... futex resumed> ) = 1 <0.000028> [pid 29114] 23:18:19.586511 write(1, "1.262156ms\n", 11 <unfinished ...> [pid 29113]Process 29162 attached (waiting for parent) <unfinished ...> [pid 29114] 23:18:19.602308 <... write resumed> ) = 11 <0.000046> [pid 29110] 23:18:19.602320 <... select resumed> ) = 0 (Timeout) <0.015898> Process 29162 resumed (parent 29109 ready) [pid 29109] 23:18:19.602336 <... fork resumed> ) = 29162 <0.015844> You can see that fork takes 15ms, and so write in another thread also takes 15ms. |
I'm going to close this in favor of the more active #5838 currently targeting Go 1.9. |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
The text was updated successfully, but these errors were encountered: