On Fri, Feb 9, 2024 at 11:57 AM Kurtis Rader <kra...@skepticism.us> wrote: > > The connect() syscall is normally blocking. It doesn't return until the > connection is established or an error occurs. It can be made non-blocking by > putting the file-descriptor into non-blocking mode before the connect() call. > However, that then requires either an async callback or another syscall to > check whether the connection was established or an error occurred. Neither > approach is idiomatic Go.
That is true, but the Go standard library's net package does use non-blocking calls to connect internally when implementing net.Dial and friends. I don't have any problem running the original program on Linux 6.5.13. Ian > On Fri, Feb 9, 2024 at 7:29 AM Venkat T V <venkat...@gmail.com> wrote: >> >> Hi, >> >> I am debugging an issue where a server opening a large number of connections >> on startup sometimes dies with "program exceeds 10000-thread limit". I know >> file IO operations could lock up an OS thread. Still seeing this crash after >> eliminating file IO, and it looks like "syscall.connect" is a blocking call >> and could tie up an OS thread. This is on Linux with golang 1.21.7. >> >> I wrote a small program to test this out. Running this with "go run >> osthreads.go -parallel 500 -threads 5" does trigger crashes sometimes, and I >> see goroutines blocked on "syscall.connect" and "syscall.fcntl". Could I get >> confirmation that this is expected behavior and Connect is a blocking >> syscall? >> >> === >> package main >> >> import ( >> "flag" >> "fmt" >> "net" >> "runtime" >> "runtime/debug" >> "sync" >> "time" >> ) >> >> func main() { >> numThreads := flag.Int("threads", 10, "number of threads (in addition to >> GOMAXPROCS)") >> parallelism := flag.Int("parallel", 100, "number of parallel goroutines to >> start") >> flag.Parse() >> >> maxThreads := runtime.GOMAXPROCS(-1) + *numThreads >> fmt.Printf("GOMAXPROCS=%d, max threads=%d\n", runtime.GOMAXPROCS(-1), >> maxThreads) >> debug.SetMaxThreads(maxThreads) >> >> // Server that does not accept any connections >> listener, err := net.Listen("tcp", "127.0.0.1:9090") >> if err != nil { >> fmt.Println(err) >> return >> } >> defer listener.Close() >> >> wg := sync.WaitGroup{} >> startSignal := make(chan struct{}) >> >> // Spawn all goroutines >> for i := 0; i < *parallelism; i++ { >> wg.Add(1) >> go func(id int) { >> defer wg.Done() >> <-startSignal >> >> conn, err := net.DialTimeout("tcp", "127.0.0.1:9090", time.Second) >> if err != nil { >> fmt.Printf("%d: error: %s\n", id, err) >> return >> } >> defer conn.Close() >> time.Sleep(time.Second) >> }(i) >> } >> >> time.Sleep(time.Second) >> >> // Start them all at once >> close(startSignal) >> wg.Wait() >> } >> >> === >> >> -- >> You received this message because you are subscribed to the Google Groups >> "golang-nuts" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to golang-nuts+unsubscr...@googlegroups.com. >> To view this discussion on the web visit >> https://groups.google.com/d/msgid/golang-nuts/33ab22bf-088a-4724-8cfb-62b7f51fca96n%40googlegroups.com. > > > > -- > Kurtis Rader > Caretaker of the exceptional canines Junior and Hank > > -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/CABx2%3DD92p6ZBjugETbX%3D5KjCqS7HH-Dv4PSuUg%3D9AZwBbioG1A%40mail.gmail.com. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAOyqgcVWPysC2vsqvXeVWmwswNBEQ5uaKQkPsZLguuiDnY_Omw%40mail.gmail.com.