8

If application does some heavy lifting with multiple file descriptors (e.g., opening - writing data - syncing - closing), what actually happens to Go runtime? Does it block all the goroutines at the time when expensive syscall occures (like syscall.Fsync)? Or only the calling goroutine is blocked while the others are still operating?

So does it make sense to write programs with multiple workers that do a lot of user space - kernel space context switching? Does it make sense to use multithreading patterns for disk input?

package main

import (
    "log"
    "os"
    "sync"
)

var data = []byte("some big data")

func worker(filenamechan chan string, wg *sync.waitgroup) {
    defer wg.done()
    for {
        filename, ok := <-filenamechan
        if !ok {
            return
        }

        // open file is a quite expensive operation due to
        // the opening new descriptor
        f, err := os.openfile(filename, os.o_create|os.o_wronly, os.filemode(0644))
        if err != nil {
            log.fatal(err)
            continue
        }

        // write is a cheap operation,
        // because it just moves data from user space to the kernel space
        if _, err := f.write(data); err != nil {
            log.fatal(err)
            continue
        }

        // syscall.fsync is a disk-bound expensive operation
        if err := f.sync(); err != nil {
            log.fatal(err)
            continue
        }

        if err := f.close(); err != nil {
            log.fatal(err)
        }
    }
}

func main() {

    // launch workers
    filenamechan := make(chan string)
    wg := &sync.waitgroup{}
    for i := 0; i < 2; i++ {
        wg.add(1)
        go worker(filenamechan, wg)
    }

    // send tasks to workers
    filenames := []string{
        "1.txt",
        "2.txt",
        "3.txt",
        "4.txt",
        "5.txt",
    }
    for i := range filenames {
        filenamechan <- filenames[i]
    }
    close(filenamechan)

    wg.wait()
}

https://play.golang.org/p/O0omcPBMAJ

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Vitaly Isaev
  • 5,392
  • 6
  • 45
  • 64
  • Related: [Number of threads used by Go runtime](http://stackoverflow.com/questions/39245660/number-of-threads-used-by-go-runtime/39246575#39246575). – icza Mar 18 '17 at 12:36
  • 1
    Also asked and being discussed [here](https://groups.google.com/d/topic/golang-nuts/NXMTsgZ_In8/discussion). – kostix Mar 18 '17 at 12:42

1 Answers1

4

If a syscall blocks, the Go runtime will launch a new thread so that the number of threads available​ to run goroutines remains the same.

A fuller explanation can be found here: https://morsmachine.dk/go-scheduler

Colin Stewart
  • 572
  • 3
  • 2