golang implements the method of concurrency control

  • 2020-06-12 09:18:28
  • OfStack

golang concurrent

Speaking of golang, it is natural to think of his concurrent goroutine. This is one of the language's proudest features. Concurrent processing, to some extent, can improve our utilization of machines and enhance the system business processing capacity. However, it is not the case that the greater the concurrency, the better, too large, the hardware environment will be unbearable, but will affect the overall performance of the system, or even crash. So, when using golang to provide convenient goroutine, you need to be able to both turn on concurrency and learn how to control it.

Enable golang concurrency

golang turns on concurrency quite simply by adding the go keyword to the front of the function when it is called. The following examples are shown:


package main
import (
  "fmt"
  "time"
)
type Demo struct {
  input     chan string
  output    chan string
  max_goroutine chan int
}
func NewDemo() *Demo {
  d := new(Demo)
  d.input = make(chan string, 24)
  d.output = make(chan string, 24)
  d.max_goroutine = make(chan int, 20)
  return d
}
func (this *Demo) Goroutine() {
  var i = 1000
  for {
    this.input <- time.Now().Format("2006-01-02 15:04:05")
    time.Sleep(time.Second * 1)
    if i < 0 {
      break
    }
    i--
  }
  close(this.input)
}
func (this *Demo) Handle() {
  for t := range this.input {
    fmt.Println("datatime is :", t)
    this.output <- t
  }
}
func main() {
  demo := NewDemo()
  go demo.Goroutine()
  demo.Handle()
}

In the above code, when the Goroutine method of Demo is called, the go keyword is added to the front to enable concurrent execution of the function Goroutine.

As you can see, turning on concurrency in golang is very convenient.

Let's take a look at how concurrency is controlled in golang.

When the concurrent tasks of goroutine reach a fixed value of 1, the main program waits for the completion of goroutine's execution and exits. Once 1 finds that the number of concurrent tasks is lower than a set value, the main program logic starts to execute again.

The implementation code is as follows:


package main
import (
  "fmt"
  "time"
)
type Demo struct {
  input     chan string
  output    chan string
  goroutine_cnt chan int
}
func NewDemo() *Demo {
  d := new(Demo)
  d.input = make(chan string, 8192)
  d.output = make(chan string, 8192)
  d.goroutine_cnt = make(chan int, 10)
  return d
}
func (this *Demo) Goroutine() {
  this.input <- time.Now().Format("2006-01-02 15:04:05")
  time.Sleep(time.Millisecond * 500)
  <-this.goroutine_cnt
}
func (this *Demo) Handle() {
  for t := range this.input {
    fmt.Println("datatime is :", t, "goroutine count is :", len(this.goroutine_cnt))
    this.output <- t + "handle"
  }
}
func main() {
  demo := NewDemo()
  go demo.Handle()
  for i := 0; i < 10000; i++ {
    demo.goroutine_cnt <- 1
    go demo.Goroutine()
  }
  close(demo.input)
}

In the example above, the Goroutine() function writes a timestamp into the pipe every 500 milliseconds, regardless of the read time of the pipe, that is, each Goroutine will have a time of about 500 milliseconds. Without control, one instant can open tens of thousands or more OF goroutine and the system will collapse.

In the above code, we introduced the chan int field with 10 buffer, writing 1 1 to the chan for each goroutine created, and popping 1 1 from chan for each goroutine completed. When chan is filled with 10 ones, it will automatically block and wait for goroutine to finish executing. When the value in chan is popped, goroutine can be started again. The maximum concurrency control of goroutine is realized by chan blocking feature.


Related articles: