Concurrent programming in Go language

Concurrency in Go language refers to the ability to make a function run independently of other functions. When a function is created as a coroutine, the Go language will treat it as an independent unit of work, which will be scheduled to be executed on the available logic processor.

Fundamentals of concurrent programming

1. Concurrency and parallelism (theory not understood)

Understanding the thread s and process es of the operating system is helpful to understand how the Go language runtime scheduler can use the operating system to run goroutine concurrently.

Parallelism is to let different code fragments execute on different physical processors at the same time. The key to parallelism is to do many things at the same time, while concurrency refers to managing many things at the same time. These things may be suspended to do other things after only half of them are done.

Using less resources to do more is the philosophy guiding Go language design.

2. Specifies the number of cores to use

Go language will call the number of CPU cores by default. These functions are automatically adjusted, but corresponding standard libraries are also provided to specify the number of cores. Using flags package, you can adjust the number of CPU cores called when the program runs.

The code is as follows:

package main

import (
	"fmt"
	"time"
)

func longWait() {
	fmt.Println("start longWait()")
	time.Sleep(5 * 1e9)
	fmt.Println("end longWait()")
}

func shortWait() {
	fmt.Println("start shortWait()")
	time.Sleep(2 * 1e9)
	fmt.Println("end shortWait()")
}

func main() {
	fmt.Println("Here is main()Where to start")
	go longWait()
	go shortWait()
	fmt.Println("Hang main()")
	time.Sleep(10 * 1e9)
	fmt.Println("Here is main()Where it ends")
}

The main(), longWait() and shortWait() functions are started in sequence as independent processing units, and then run in parallel. Each function outputs messages at the beginning and end of the run.

The operation results are as follows:

Here is main()Where to start
 Hang main()
start longWait()
start shortWait()
end shortWait()
end longWait()
Here is main()Where it ends

If you remove the go language keyword, run the program again:

Here is main()Where to start
 start longWait()
end longWait()
start shortWait()
end shortWait()
Hang main()
Here is main()Where it ends

goroutine

The operating system is in charge of the process, the thread in the process and the coroutine in the process.

The biggest advantage of collaborative process is its "lightweight", which can easily create millions of collaborative processes without causing system resource exhaustion, and the maximum number of threads and processes can not exceed 10000.

Go language supports lightweight threads at the language level, called goroutine.

1. Synergetic basis

goroutine is the core of Go language parallel design.

goroutine is a thread manager managed through the runtime of the Go program. goroutine is implemented through the go keyword. In fact, it is an ordinary function.

The code is as follows:

package main

import (
	"fmt"
	"runtime"
)

func say(s string) {
	for i := 0; i < 5; i++ {
		runtime.Gosched()
		fmt.Println(s)
	}
}

func main() {
	go say("world")
	say("hello")
}

The running results are as follows: different from books.

hello
hello
hello
hello
hello

Books are:

hello
world
hello
world
hello
world
hello
world
hello

2. Inter process communication

There are usually two most common concurrent communication models: shared data and messages.

The code is as follows:

package main

import (
	"fmt"
	"runtime"
	"sync"
)

var counter int = 0

func Count(lock *sync.Mutex) {
	lock.Lock()
	counter++
	fmt.Println(z)
	lock.Unlock()
}

func main() {
	lock := &sync.Mutex{}
	for i := 0; i < 10; i++ {
		go Count(lock)
	}
	for {
		lock.Lock()
		c := counter
		lock.Unlock()
		runtime.Gosched()
		if c >= 10 {
			break
		}
	}
}

The operation results are as follows:

# command-line-arguments
./main.go:14:14: undefined: z

Do not communicate through shared memory, but share memory through communication.

Channel

The code is as follows:

package main

import (
	"fmt"
)

func Count(ch chan int) {
	ch <- 1
	fmt.Println("Counting")
}

func main() {
	chs := make([]chan int, 10)
	for i := 0; i < 10; i++ {
		chs[i] = make(chan int)
		go Count(chs[i])
	}
	for _, ch := range chs {
		<-ch
	}
}

1. Basic grammar

The general declaration form of channel is:

var chanName chan ElementType

In the usage of channel, the most common include write and read.

The syntax of writing (sending) a data to the channel is very intuitive:

ch <- value

The syntax of reading data from channel is:

value:=<-ch

2,select

Go language directly supports the select keyword at the language level, which is used to deal with asynchronous I/O problems.

3. Buffer mechanism

4. Timeouts and timers

5. Transmission of channel

6. Unidirectional channel

7. Close channel

Use the close() function built in go language as follows:

close(ch)

Concurrent advanced

1. Multi core parallelization

2. Co process synchronization

The channel needs to be closed only when the receiver needs to be told that it will no longer provide new values.

Only the sender needs to close the channel, and the receiver will never need it.

The code is as follows:

package main

import (
	"fmt"
	"time"
)

func sendData(ch chan string) {
	ch <- "New York"
	ch <- "Washington"
	ch <- "London"
	ch <- "Beijing"
	ch <- "Tokyo"
}

func getData(ch chan string) {
	var input string
	for {
		input = <-ch
		fmt.Printf("%s ", input)
	}
}

func main() {
	ch := make(chan string)
	go sendData(ch)
	go getData(ch)
	time.Sleep(1e9)
}

The operation results are as follows:

New York Washington London Beijing Tokyo 

The code is as follows:

package main

import (
	"fmt"
)

func sendData(ch chan string) {
	ch <- "New York"
	ch <- "Washington"
	ch <- "London"
	ch <- "Beijing"
	ch <- "Tokyo"
	close(ch)
}

func getData(ch chan string) {
	for {
		input, open := <-ch
		if !open {
			break
		}
		fmt.Printf("%s ", input)
	}
}

func main() {
	ch := make(chan string)
	go sendData(ch)
	getData(ch)
}

The operation results are as follows:

New York Washington London Beijing Tokyo 

Keywords: Go Back-end

Added by polybiosis on Thu, 03 Feb 2022 21:15:46 +0200