The use of Golang Goroutine

  • 2020-11-20 06:08:00
  • OfStack

What is a Goroutine

goroutine is the core of Go's parallel design. goroutine is essentially a coroutine. It's smaller than threads. A dozen or so goroutine might be 56 threads at the bottom.

goroutine requires very little stack memory (about 4 to 5KB) to execute, and of course scales accordingly. Because of this, thousands of concurrent tasks can be run simultaneously. The goroutine is easier to use, more efficient and lighter than the thread.

Under normal circumstances, a typical computer running a few dozen threads would be a bit overloaded, but the same machine could easily have hundreds or thousands of goroutine competing for resources.

The creation of Goroutine

Just call the function ⽤ Add the go keyword before the statement to create concurrency ⾏ Unit.

Development & # 12040; The staff need not know any grasping ⾏ The scheduler will automatically assign it to the appropriate system thread for execution.

In concurrent programming, we usually want to split a procedure into several pieces and have each goroutine responsible for one block of work. When a program starts, the main function runs in a separate goroutine, which we call main goroutine. The new goroutine will be created using the go statement. The concurrent design of the go language makes it easy to achieve this goal.

Such as:


package main

import (
 "fmt"
 "time"
)

func foo() {
 i := 0
 for true {
 i++
 fmt.Println("new goroutine: i = ", i)
 time.Sleep(time.Second)
 }
}

func main() {
 //  create 1 a  goroutine,  The other 1 A task 
 go foo()

 i := 0
 for true {
 i++
 fmt.Println("main goroutine: i = ", i)
 time.Sleep(time.Second)
 }
}

Results:

[

main goroutine: i = 1
new goroutine: i = 1
new goroutine: i = 2
main goroutine: i = 2
main goroutine: i = 3
new goroutine: i = 3
...

]

Goroutine features

After the main go program exits, other sub-ES68en programs will exit automatically:


package main

import (
 "fmt"
 "time"
)

func foo() {
 i := 0
 for true {
 i++
 fmt.Println("new goroutine: i = ", i)
 time.Sleep(time.Second)
 }
}

func main() {
 //  create 1 a  goroutine,  The other 1 A task 
 go foo()

 time.Sleep(time.Second * 3)

 fmt.Println("main goroutine exit")
}

Operation results:

[

new goroutine: i = 1
new goroutine: i = 2
new goroutine: i = 3
main goroutine exit

]

runtime package

Gosched

runtime. Gosched() is used to transfer the CPU time slice occupied by the current go procedure, to give up the execution permission of the current goroutine, to arrange other waiting tasks to run, and to resume execution from the position of the transferred cpu the next time the cpu time slice is acquired.

A bit like a relay race, A runs 1 and touches the code ES104en.Gosched () and passes the baton to B. A rests, B runs on.

Such as:


package main

import (
 "fmt"
 "runtime"
 "time"
)

func main() {
 //  create 1 a  goroutine
 go func(s string) {
 for i := 0; i < 2; i++ {
  fmt.Println(s)
 }
 }("world")

 for i := 0; i < 2; i++ {
 runtime.Gosched()
 fmt.Println("hello")
 }
 time.Sleep(time.Second * 3)
}

Operation results:

[

world
world
hello
hello

]

If runtime. Gosched() is not present, the result of the run is as follows:

[

hello
hello
world
world

]

Note: ES144en. Gosched() only gives one chance. Look at the code below and notice the result:


package main

import (
 "fmt"
 "runtime"
 "time"
)

func main() {
 //  create 1 a  goroutine
 go func(s string) {
 for i := 0; i < 2; i++ {
  fmt.Println(s)
  time.Sleep(time.Second)
 }
 }("world")

 for i := 0; i < 2; i++ {
 runtime.Gosched()
 fmt.Println("hello")
 }
}

Operation results:

[

world
hello
hello

]

Why is world only once? Because as we said before, when master goroutine quits, other work goroutine quits automatically.

Goexit

Calling ES170en.Goexit () immediately terminates the current goroutine hold ⾏ , the scheduler ensures that all registered defer deferred calls are executed.

Note the difference with return, which returns the current function call to the caller.

Such as:


package main

import (
 "fmt"
 "runtime"
 "time"
)

func main() {
 go func() {
 defer fmt.Println("A.defer")
 func() {
  defer fmt.Println("B.defer")
  runtime.Goexit() //  Termination of the current  goroutine
  fmt.Println("B") //  Do not perform 
 }()
 fmt.Println("A") //  Do not perform 
 }() //  Don't forget  ()

 time.Sleep(time.Second * 3)
}

Operation results:

[

B.defer
A.defer

]

GOMAXPROCS

The call to runtime.GOMAXPROCS () is used to set the maximum number of CPU checks that can be computed in parallel, and returns the value set the previous time (if not the computer's default).


package main

import (
 "fmt"
 "runtime"
)

func main() {
 runtime.GOMAXPROCS(1) //  will  cpu  Set to a single core 

 for true {
 go fmt.Print(0) //  The child  go  cheng 
 fmt.Print(1) //  The main  go  cheng 
 }
}

Operation results:

[

111111 ... 1000000 ... 0111 ...

]

When runtime.GOMAXPROCS (1) is executed, at most one goroutine is executed at a time. So it's going to print a lot of 1s. After a period of time, the GO scheduler will put it to sleep and wake up another goroutine, at which time it will start printing a lot of zeros. At the time of printing, goroutine is scheduled to the operating system thread.


package main

import (
 "fmt"
 "runtime"
)

func main() {
 runtime.GOMAXPROCS(2)

 for true {
 go fmt.Print(0)
 fmt.Print(1)
 }
}

Operation results:

[

111111111111111000000000000000111111111111111110000000000000000011111111100000...

]

In the implementation runtime.GOMAXPROCS(2) , we used two CPU, so both goroutine can be executed 1 at a time, printing 0 and 1 alternately at the same frequency.

Other functions in the runtime package

Chinese document here: https: / / studygolang com/pkgdoc

Here is a simple list of functions and functions.


func GOROOT() string

GOROOT returns the root directory of Go. If an GOROOT environment variable exists, return the value of that variable. Otherwise, return the root directory where Go was created.


func Version() string

Returns the version string of Go. It is either hash submitted and the date it was created; Or release labels such as "go1.3".


func NumCPU() int

NumCPU returns the number of logical CPU Numbers (true · 8 cores) for the local machine.


package main

import (
 "fmt"
 "time"
)

func foo() {
 i := 0
 for true {
 i++
 fmt.Println("new goroutine: i = ", i)
 time.Sleep(time.Second)
 }
}

func main() {
 //  create 1 a  goroutine,  The other 1 A task 
 go foo()

 time.Sleep(time.Second * 3)

 fmt.Println("main goroutine exit")
}

0

GC performs a garbage collection once. (Call this function if you are desperate to do a garbage collection)


Related articles: