当前位置:网站首页>[go] goroutine pool

[go] goroutine pool

2022-06-21 14:54:00 Cabbage that wants to become powerful


One 、 Why Goroutine pool ?

Imagine a situation like this , If you assign one to each client session To maintain the connection , Then each session It will start 3 individual goroutine, One for reading messages , One for sending messages , One is used to detect the life cycle . that , When a large number of clients connect , that goroutine The quantity is 3 Times the number of clients . Even if goroutine Lighter weight , When millions of customers are pouring in , Memory can't be stretched .

golang It is said that it can be concurrent at millions of levels , but goroutine It should not be created without restrictions , After all, every time you request memory from the system , The system memory will run out one day . Is there anything like a pool , It can make goroutine Can be reused , There is no need for unrestrained creation ?

in other words , What can be done to slow down the scale Goroutine Scheduling and memory pressure on the system ? To solve the problem , The most important thing is to find the root cause of the problem , What is the root of the problem ?Goroutine Too many lead to resource encroachment , To solve this problem, we need to limit the operation of Goroutine Number , Reasonable reuse , Save resources , The concrete is — Goroutine Pooling .

This is the birth of Goroutine The concept of a pool .Goroutine Pool is not golang An official concept , It is a solution to the above problems found by programmers in practice goroutine When the actual problems arising from the train of thought .

Just imagine ,Goroutine A certain number of... Are stored in the pool in advance Goroutine , New tasks will no longer create new Goroutine The way to execute , Instead, publish the task to the task queue ,Goroutine In the pool Goroutine Constantly take out tasks from the task queue and execute , Can effectively reduce Goroutine The overhead of creating and destroying .

Summarize why you want to achieve Goroutine pool :

  • Even if each goroutine Just assign 4KB Of memory , But if it's that amount of terror , many a little make a mickle , Memory usage will be too high .
  • Would be right GC Create a great burden , First GC Will be recycled goroutine On consumption performance , secondly GC Itself is also goroutine , The memory is tight GC There will be problems in the scheduling of .
  • Improve response time , Reduce the time to create a collaboration .
  • Better management coordination , Control the maximum number of concurrent , Regular recycling .

Two 、Goroutine What is a pool ?

  1. Goroutine A pool is a pool , There's some in there Goroutine .
  2. This pool has a maximum capacity , Inside Goroutine The quantity cannot exceed its maximum capacity .
  3. You can put every in the pool Goroutine Think of it as a worker , Used to perform tasks .

More precisely ,Goroutine A pool is an architecture . The architecture consists of two parts :

  1. A pool , There's some in there Goroutine .
  2. A task queue , There are some for the pool Goroutine Tasks performed .

A new task has come , If the pool is full Goroutine , And they all work , Then put the task in the task queue , Waiting to be dealt with ;
If the pool is not full , Just open a new one Goroutine To handle the task .


3、 ... and 、 How to achieve Goroutine pool ?

1. Goroutine Pool is just an abstract concept

Golang There is no encapsulated thread pool .

Goroutine Pool is just a concept , We need to consciously implement when we write our own code Goroutine pool .

2. Goroutine The design idea of the pool

  1. Initialize a when starting the service Goroutine Pool, This process pool maintains Task pipeline and worker( That is to say Goroutine).
  2. External post request to Goroutine Pool,Goroutine Pool The operation of : Determine the current running worker Has it exceeded Pool The capacity of , If it exceeds, put the request into the task pipeline until it runs worker Execute the tasks in the pipeline ; If not, open a new one worker Handle .

3. Producer consumer model

In this The delivery —> wait for —> perform In the process of , It is easy to think of the producer consumer model :

producer --( Production task )–> queue --( Consumption task )–> consumer

actually , Used to perform tasks goroutine It's the consumer , Operation task pool goroutine It's the producer , Queues can use go Of buffer channel, thus , This is the end of the task pool modeling .


Four 、 An implementation Goroutine Examples of pools

subject :

  1. Calculate the sum of the digits of a number , For example, digital 123, The result is 1+2+3=6.
  2. Randomly generated numbers for calculation .
package main

import (
	"fmt"
	"math/rand"
)

type Job struct {
     // Mission 
	// id
	Id int
	//  Random number to be calculated 
	RandNum int
}

type Result struct {
     // result 
	//  The object instance must be passed here 
	job *Job
	//  Sum up 
	sum int
}

func main() {
    
	//  need 2 A pipe 
	//  Mission pipeline 
	jobChan := make(chan *Job, 128)
	//  Result pipeline 
	resultChan := make(chan *Result, 128)
	
	//  Work pool (goroutine pool )
	createPool(64, jobChan, resultChan) // There are... In the working pool 64 individual Goroutine at work 
	
	
	//  Responsible for the printing process 
	go func(resultChan chan *Result) {
    
		//  Traverse the result pipeline , Print 
		for result := range resultChan {
     // From the tunnel resultChan Receives the value 
			fmt.Printf("job id:%v randnum:%v result:%d\n", result.job.Id,
				result.job.RandNum, result.sum)
		}
	}(resultChan) // Pass in parameters to the function , Execute now 

	// Main process 
	var id int
	//  Loop creation job, Input to pipeline 
	for {
    
		id++
		//  Generate random number 
		r_num := rand.Int()
		job := &Job{
    
			Id:      id,
			RandNum: r_num,
		}
		jobChan <- job
	}
}

//  function createPool: Create a work pool 
//  In the working pool Goroutine Responsible for calculating from jobChan Take the number , Then calculate the sum of all of you , And then output to resultChan
func createPool(num int, jobChan chan *Job, resultChan chan *Result) {
    
	//  open  num  Collaborators cheng , Do calculations 
	for i := 0; i < num; i++ {
    
		go func(jobChan chan *Job, resultChan chan *Result) {
    
			//  Perform an operation 
			//  Traverse job All data of the pipeline , Add additivity 
			for job := range jobChan {
    
				//  Random numbers come in 
				r_num := job.RandNum // Read random number 
				//  Each bit of random number is added 
				//  Define the return value 
				var sum int
				for r_num != 0 {
    
					tmp := r_num % 10
					sum += tmp
					r_num /= 10
				}
				//  The desired result is Result
				r := &Result{
    
					job: job,
					sum: sum,
				}
				// The result of the calculation is thrown into the pipe 
				resultChan <- r
			}
		}(jobChan, resultChan)
	}
}

The tip of the iceberg :

job id:62596 randnum:3542998448878732054 result:100
job id:62597 randnum:1412622303680101805 result:53
job id:62598 randnum:2405699357934002636 result:83
job id:62599 randnum:729922549175030513 result:74
job id:62600 randnum:8887708274878274993 result:116
job id:62601 randnum:5826041766204926306 result:77
job id:62602 randnum:5892735228296506585 result:97
job id:62603 randnum:5715834663741984020 result:83
job id:62604 randnum:3141293823040601058 result:60
job id:62605 randnum:8841672571116882462 result:87
job id:62606 randnum:3482484307097615774 result:89
job id:62607 randnum:8196261471617693666 result:95
job id:62608 randnum:8692192048687145566 result:97
job id:62609 randnum:2639146648002715963 result:82
job id:62610 randnum:3323717745941790047 result:83
job id:62611 randnum:7567210708242192793 result:82

explain :

Pictured above , This procedure consists of two processes 、 A collaborative process pool 、 Two pipes make up .

job The coordination process continuously produces tasks , And then put in jobchan Task queue ; There are... In the process pool 64 Collaborators cheng , Constantly from the task queue jobchan Take the task to execute , Put the results in resultchan Task queue ;printf Assist from resultchan Take the results from the task queue and print them .

among , We can see two pairs of producers and consumers :job Synergy and synergy pool are a pair of producers and consumers , Process pool and printf Xiecheng is also a pair of producers and consumers .

explain :
In this case , The two pipelines and the process pool can be understood as “Goroutine pool ”.
Its function is always limited Goroutine Quantity is an unlimited amount of work .

Just imagine , If there are no these two pipelines and process pools :
job The collaboration process has been generating tasks , To perform a task, you need to create a coroutine to calculate it … That would be a myriad of collaborations …


5、 ... and 、 One Goroutine Pool practice —— ants

Project address :ants

Alibaba cloud's recommendation : It's easy to recommend Goroutine Connection pool


6、 ... and 、 summary

worker pool(goroutine pool ):

  1. It's essentially a producer consumer model
  2. Can effectively control goroutine Number , Prevent inflation

Reference link

  1. Goroutine pool
  2. golang Of goroutine pool ( Thread pool )
  3. Goroutine Pool implementation
  4. [go Language ]go goroutine Scheduling mechanism && goroutine pool
  5. The article of the boss is worth reading carefully :Goroutine In depth analysis of concurrent scheduling model provides a high performance Goroutine pool
原网站

版权声明
本文为[Cabbage that wants to become powerful]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202221334003116.html