Is the main function run a goroutine? - go

Is the main() function a goroutine? For example, I've seen a crash stack trace like the below, which makes me ask:
goroutine 1 [running]: main.binarySearch(0x0, 0x61, 0x43,
0xc420043e70, 0x19, 0x19, 0x10)
/home/---/go/src/github.com/----/sumnum.go:22 +0x80 main.main()
/home/---/go/src/github.com/---/sumnum.go:13 +0xc1 exit status 2

Is the main function a goroutine?
No.
The main function is a function.
In contrast,
A goroutine is a lightweight thread of execution. (source).
So goroutines execute functions, but goroutines are not functions, and there is not a 1-to-1 relationship between goroutines and functions.
However...
The main() function is executed in the first (and at startup, only) goroutine, goroutine #1.
But as soon as that function calls another function, then the main goroutine is no longer executing the main function, and is instead executing some other function.
So it's clear that a goroutine and a function are entirely different entities.
Do not conflate goroutines with functions!!
Functions and goroutines are entirely different concepts. And thinking of them as the same thing will lead to countless confusion and problems.

Yes, the main function runs as a goroutine (the main one).
According to https://tour.golang.org/concurrency/1
A goroutine is a lightweight thread managed by the Go runtime.
go f(x, y, z)
starts a new goroutine running f(x, y, z) The evaluation of f, x, y, and z happens in the current goroutine and the execution of f happens in the new goroutine.
Goroutines run in the same address space, so access to shared memory must be synchronized. The sync package provides useful primitives, although you won't need them much in Go as there are other primitives.
So according to this official document the main is the current goroutine.
To be precise (literally) we could address the main as the current goroutine, so simply speaking it is a goroutine. (Note: Literally speaking the main() is a function which could run as a goroutine.)
Now let's count the number of goroutines using runtime.NumGoroutine():
As an example let's run 3 goroutines. Try it online:
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
fmt.Println(runtime.NumGoroutine()) // 3
time.Sleep(100 * time.Millisecond)
}
func init() {
go main()
go main()
}
Here the current goroutine runs the new goroutine, so here we have more than one goroutine, which executes main() again. Try it online:
package main
import (
"fmt"
"runtime"
"sync/atomic"
"time"
)
func main() {
fmt.Println(runtime.NumGoroutine()) // 1 2 3 4
if atomic.LoadInt32(&i) <= 0 {
return
}
atomic.AddInt32(&i, -1)
go main()
time.Sleep(100 * time.Millisecond)
}
var i int32 = 3
Output:
1
2
3
4
Here we have one main goroutine plus 3 user called main goroutines, so total number of goroutines are 4 here.
Let's calculate factorial using main() (one goroutine - no synchronization needed). Try it online:
package main
import "fmt"
func main() {
if f <= 0 {
fmt.Println(acc)
return
}
acc *= f
f--
main()
}
var f = 5
var acc = 1
Output:
120
Note: The codes above are just for clearly showing my viewpoints and is not good for production use (Using global variables should not be the first choice).

Yes. Main func can spawn other goroutines, but "main" itself is one groutine.
package main
import (
"fmt"
"runtime"
)
func main() {
// Goroutine num includes main processing
fmt.Println(runtime.NumGoroutine()) // 1
// Spawn two goroutines
go func() {}()
go func() {}()
// Total three goroutines run
fmt.Println(runtime.NumGoroutine()) // 3
}

Related

Most simple Go race-condition example?

I need a simple Go code sample which will definitely run the program into an race-condition.
Any ideas?
The original question:
I need a simple Go code sample which will definitely run the program
into an race-condition.
For example,
racer.go:
package main
import (
"time"
)
var count int
func race() {
count++
}
func main() {
go race()
go race()
time.Sleep(1 * time.Second)
}
Output:
$ go run -race racer.go
==================
WARNING: DATA RACE
Read at 0x00000052ccf8 by goroutine 6:
main.race()
/home/peter/gopath/src/racer.go:10 +0x3a
Previous write at 0x00000052ccf8 by goroutine 5:
main.race()
/home/peter/gopath/src/racer.go:10 +0x56
Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:15 +0x5a
Goroutine 5 (finished) created at:
main.main()
/home/peter/gopath/src/racer.go:14 +0x42
==================
Found 1 data race(s)
exit status 66
$
package main
import (
"fmt"
)
func main() {
i := 0
// Run forever to make it to show race condition
for {
var x, y int
// Set x to 60
go func(v *int) {
*v = 60
}(&x)
// Set y to 3
go func(v *int) {
*v = 3
}(&y)
/*
A race condition is when multiple threads are trying to access and manipulate the same variable.
the code below is all accessing and changing the value.
Divide x (60) by y (3) and assign to z (42)...
Except if y is not assigned 3 before x is assigned 60,
y's initialized value of 0 is used,
Due to the uncertainty of the Goroutine scheduling mechanism, the results of the following program is unpredictable,
which causes a divide by zero exception.
*/
go func(v1 int, v2 int) {
fmt.Println(v1 / v2)
}(x, y)
i += 1
fmt.Printf("%d\n", i)
}
}
Run code using: go run -race .go

Concurrent access to variable without lock

I was disturbed by a question,
should we add lock if only one thread write variable, and other thread just read variable?
so I write such code to test it
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
var lock sync.RWMutex
var i = 0
func main() {
runtime.GOMAXPROCS(2)
go func() {
for {
fmt.Println("i am here", i)
time.Sleep(time.Second)
}
}()
for {
i += 1
}
}
The result is keep print i am here 0 even after second of time. I know a little about Memory barrier or cpu cache. but how could it be cache for such a long time? I think after a few time, it should read variable I already changed.
Can anyone who is master go or computer system could help answer, please?
Update: i know it is a wrong way to update variable like this, i want to know why it is undefined in cpu/memory view.
You have a data race. Therefore, the results are undefined.
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
var lock sync.RWMutex
var i = 0
func main() {
runtime.GOMAXPROCS(2)
go func() {
for {
fmt.Println("i am here", i)
time.Sleep(time.Second)
}
}()
for {
i += 1
}
}
Output:
$ go run -race racer.go
==================
WARNING: DATA RACE
Read at 0x0000005e3600 by goroutine 6:
main.main.func1()
/home/peter/gopath/src/racer.go:17 +0x63
Previous write at 0x0000005e3600 by main goroutine:
main.main()
/home/peter/gopath/src/racer.go:22 +0x7b
Goroutine 6 (running) created at:
main.main()
/home/peter/gopath/src/racer.go:15 +0x4f
==================
i am here 3622
i am here 43165250
i am here 86147697
^Csignal: interrupt
$
References:
Data Race Detector
Benign Data Races: What Could Possibly Go Wrong?
should we add lock if only one thread write variable, and other thread just read variable?
Yes. Always. No arguing here.
Your test code proves and disproves nothing as its behaviour is undefined.
finally, i find this answers, i know with a data race you will get a undefined behave, but i want to know why it behave like that currently.
this snap code is because complier just remove Add function, it never add.
so we have lesson, if you write a undefined behave, you may got a moon - -
complier will treat you code as rubbish, it does not have any value.

why the "infinite" for loop is not processed?

I need to wait until x.Addr is being updated but it seems the for loop is not run. I suspect this is due the go scheduler and I'm wondering why it works this way or if there is any way I can fix it(without channels).
package main
import "fmt"
import "time"
type T struct {
Addr *string
}
func main() {
x := &T{}
go update(x)
for x.Addr == nil {
if x.Addr != nil {
break
}
}
fmt.Println("Hello, playground")
}
func update(x *T) {
time.Sleep(2 * time.Second)
y := ""
x.Addr = &y
}
There are two (three) problems with your code.
First, you are right that there is no point in the loop at which you give control to the scheduler and such it can't execute the update goroutine. To fix this you can set GOMAXPROCS to something bigger than one and then multiple goroutines can run in parallel.
(However, as it is this won't help as you pass x by value to the update function which means that the main goroutine will never see the update on x. To fix this problem you have to pass x by pointer. Now obsolete as OP fixed the code.)
Finally, note that you have a data race on Addr as you are not using atomic loads and stores.

How to identify the stack size of goroutine?

I know go routine can have a few blocking actions, wonder if a goroutine can call a user-defined blocking function like a regular function. A user-defined blocking function has a few steps like, step1, step2.
In another word, I would like to find out whether we can have nested blocking calls in a go routine.
UPDATE:
Original intention was to find the stack size used by goroutine, especially with nested blocking calls. Sorry for the confusion. Thanks to the answer and comments, I created the following function that has 100,000 goroutines, it took 782MB of virtual memory and 416MB of Resident memory on my Ubuntu desktop. It evens out to be 78KB of memory for each go routine stack. Is this a correct statement?
package main
import (
"fmt"
"time"
)
func f(a int) {
x := f1(a);
f2(x);
}
func f1(a int) int {
r := step("1a", a);
r = step("1b", r);
return 1000 * a;
}
func f2(a int) {
r := step("2a", a);
r = step("2b", r);
}
func step(a string, b int) int{
fmt.Printf("%s %d\n", a, b);
time.Sleep(1000 * time.Second)
return 10 * b;
}
func main() {
for i := 0; i < 100000; i++ {
go f(i);
}
//go f(20);
time.Sleep(1000 * time.Second)
}
I believe you're right, though I'm unsure of the relationship between "virtual" and "resident" memory it's possible there's some overlap.
Some things to consider: you're running 100,000 it appears, not 10,000.
The stack itself might contain things like the strings used for the printfs, method parameters, etc.
As of go 1.2 the default stack size (per go routine) is 8KB which may explain some of it.
As of go 1.3 it also uses an exponentially increasing stack size, but I doubt that's the problem you're running into.
Short answer yes.
A goroutine is a "lightweight thread", that means it can do stuff independently from other code in your program. It's almost as if you started a new program, but you can communicate with your other code using the constructs golang provides (channels, locks, etc.).
P.S. Once the main function ends, all goroutines are killed (that's why you need the time.Sleep() in the example)
Here's the quick example (won't run in the golang playground because of their constraints):
package main
import (
"fmt"
"time"
)
func saySomething(a, b func()){
a()
b()
}
func foo() {
fmt.Println("foo")
}
func bar() {
fmt.Println("bar")
}
func talkForAWhile() {
for {
saySomething(foo, bar)
}
}
func main() {
go talkForAWhile()
time.Sleep(1 * time.Second)
}

Golang: goroutine infinite-loop

When an fmt.Print() line is removed from the code below, code runs infinitely. Why?
package main
import "fmt"
import "time"
import "sync/atomic"
func main() {
var ops uint64 = 0
for i := 0; i < 50; i++ {
go func() {
for {
atomic.AddUint64(&ops, 1)
fmt.Print()
}
}()
}
time.Sleep(time.Second)
opsFinal := atomic.LoadUint64(&ops)
fmt.Println("ops:", opsFinal)
}
The Go By Example article includes:
// Allow other goroutines to proceed.
runtime.Gosched()
The fmt.Print() plays a similar role, and allows the main() to have a chance to proceed.
A export GOMAXPROCS=2 might help the program to finish even in the case of an infinite loop, as explained in "golang: goroute with select doesn't stop unless I added a fmt.Print()".
fmt.Print() explicitly passes control to some syscall stuff
Yes, go1.2+ has pre-emption in the scheduler
In prior releases, a goroutine that was looping forever could starve out other goroutines on the same thread, a serious problem when GOMAXPROCS provided only one user thread.
In Go 1.2, this is partially addressed: The scheduler is invoked occasionally upon entry to a function. This means that any loop that includes a (non-inlined) function call can be pre-empted, allowing other goroutines to run on the same thread.
Notice the emphasis (that I put): it is possible that in your example the for loop atomic.AddUint64(&ops, 1) is inlined. No pre-emption there.
Update 2017: Go 1.10 will get rid of GOMAXPROCS.

Resources