goroutine one process bug in golang

480 views Asked by At

I am studying about golang.

in golang, there is a concept, called goroutine. i write a sample code.

package main

import (
    "fmt"
    "runtime"
)

func main() {
    runtime.GOMAXPROCS(1) // cpu core를 하나만 사용하도록 해 놓음

    s := "test string"

    for i := 0; i < 100; i++ {
        go func(n int) {
            fmt.Println(s, n)
        }(i)
    }

    fmt.Scanln()
}

if you interpret code and run, you will see first printing data is

test string 99

I don't know why result it is. Anyone help me?

2

There are 2 answers

4
Mario Santini On

It is because of this line:

runtime.GOMAXPROCS(1)

As the goroutine are a way to execute code concurrently, all the goroutine you create in your loop have to wait for a proc.

As you have just one, and it is busy executing the loop, you're going to have a stack of goroutine waiting.

When the loops ends the proc have time to execute the first goroutine, that is the last created, and then do the same thing whith the stack one by one, but this time in sequence.

Try to put 2 procs and look what will happen.

Keep in mind that when you work in concurrent the order in which the code is executed is not guarantee, as already has been mentioned in a comment.

Here you have a sequence, just because you have just one process.

If your purpose is to have items processed sequencially even in a concurrent way, you should use channels.

Let me show a sample of code that do the job:

package main

import (
    "fmt"
    "runtime"
)

func printNumbers(text string, ns chan int) {
    for n := range ns {
        fmt.Println(text, n)
    }
}

func main() {
    runtime.GOMAXPROCS(1) // cpu core를 하나만 사용하도록 해 놓음

    s := "test string"

    numbers := make(chan int)

    go printNumbers(s, numbers)

    go func() {
        for i := 0; i < 100; i++ {
            numbers <- i
        }
        close(numbers)
    }()

    fmt.Scanln()
}

As you can see is just a new version of your, but if you execute you should get the proper sequence.

The main changes are that you have 2 goroutine now, one for the print and one for the loop.

The 2 goroutine talk throungh a channel of int.

When the program start the first goroutin call the function printNumbers, that stai waiting until something is written into the channel.

Then start the second gorouting that write one by one the integers into the channel.

Once the for is ended, as you have just 1 process, the printNumbers function start again as there are items inside the channel.

It loops until it end the itmes.

Of course, you have 2 loops here, but you can't avoid it.

So now try to ass process as you wish and look what happen.

2
Yandry Pozo On

Your question is a good one and the answer is basically how the internal runtime Go Scheduler works, but as Mario Santini says the order of execution isn't guarantee.

In my limited words I can tell you that the Go Scheduler depends of what kind of process scheduler algorithm https://en.wikipedia.org/wiki/Scheduling_(computing) is used internally and based on that it will decide how much time executed and the order of each goroutine asking to run, also it'll create OS threads for you as necessary, in your case you are limiting to only 1, so it'll not be parallel at all, so obviously the last goroutine is getting lucky enough to be run it as the first one.

I leave you some links with better explanations:

https://www.quora.com/How-does-the-golang-scheduler-work http://www.sarathlakshman.com/2016/06/15/pitfall-of-golang-scheduler http://www.slideshare.net/matthewrdale/demystifying-the-go-scheduler