当前位置:网站首页>Go language context explanation

Go language context explanation

2022-07-07 05:43:00 Heavy dust

GO In language Context Bao explained in detail

Author mogd 2022-06-28
Update mogd 2022-07-04
Adage Rreality is merely an illusion, albeit a very persistent one.

Preface

I don't know if there are any friends like me , I'm learning go When language is basic , Meet the need context The information of , It's all direct context.TODO(), No further study Context

Let the author deeply understand Context It's because I'm writing a K8S CMDB Platform time , Think of the need to initialize the data ( Is to create admin user , And test users , And assign corresponding Casbin jurisdiction )

because user The module references gin-vue-admin, And in GVA There is also a data initialization part in , This part of the code uses Context

Read it carefully , That's right Context Bao has a deeper understanding

Studying hard is often just knowing its shape but not its meaning , Only by actually doing projects can we really master a language

The author wrote a K8S CMDB Platform backend interface ,gin-kubernetes
This is just beginning to write , It's very simple , You can have a look at what you are interested in ; I also hope the big guys can make suggestions
user Module reference gin-vue-admin

One 、Context Introduce

1.1 Context What is it? ?

Context stay Go1.7 Then join Go In the language standard library , yes Goroutine The context of , contain Goroutine Operating state 、 Environmental Science 、 Information about the scene

In Go servers, each incoming request is handled in its own goroutine. Request handlers often start additional goroutines to access backends such as databases and RPC services. The set of goroutines working on a request typically needs access to request-specific values such as the identity of the end user, authorization tokens, and the request’s deadline. When a request is canceled or times out, all the goroutines working on that request should exit quickly so the system can reclaim any resources they are using.
At Google, we developed a context package that makes it easy to pass request-scoped values, cancellation signals, and deadlines across API boundaries to all the goroutines involved in handling a request

Go In the service of , Each request will have its own goroutine Handle , Every goroutine Usually start a new goroutine Perform some extra work , Such as database or RPC Access to services . Same as in the request goroutine Need to be able to share request data access , such as , User authentication , to grant authorization token, And request deadline . If the request is canceled or a timeout occurs , All within the scope of the request goroutine Should quit immediately , Recycling
stay Google, We developed a context My bag , Through it , We can easily request goroutine Transfer request data between 、 Cancel signal and timeout information

Judging from the official introduction ,Context Package for goroutine To send messages . It's with us goroutine Used between channel It's like , But it's different . Because in different goroutine Only done channel It contains too little information

And with Context Package Introduction , Many interfaces of the standard library are added Context Parameters ,Context Almost become the standard practice of concurrency control and timeout control

Context Use scenarios

  • Context messaging (request-scoped), For example, deal with http request 、 Passing information along the request processing chain
  • The controller goroutine Operation of
  • Timeout control method call
  • Method calls that can be cancelled

1.2 Context Interface

context The core is Context type

// A Context carries a deadline, cancellation signal, and request-scoped values
// across API boundaries. Its methods are safe for simultaneous use by multiple
// goroutines.
type Context interface {
    
    // Done returns a channel that is closed when this Context is canceled
    // or times out.
    Done() <-chan struct{
    }

    // Err indicates why this context was canceled, after the Done channel
    // is closed.
    Err() error

    // Deadline returns the time when this Context will be canceled, if any.
    Deadline() (deadline time.Time, ok bool)

    // Value returns the value associated with key or nil if none.
    Value(key interface{
    }) interface{
    }
}
  • Done Method returns a channel, It can be used to receive context The cancellation signal of . When channel close , monitor Done The function of the signal will immediately give up the work currently being performed and return
  • Err Method returns a error Variable , From it we can know context Why was it cancelled .pipeline and cancelation One article is right Done channel Made a detailed introduction
  • Deadline Method lets the function decide whether to start work , If the remaining time is too short , Then starting the work is not worth it . In the code , We can go through deadline by IO Operation set timeout
  • Value Method can make context stay goroutine Share data within the scope of the request , These data need to be concurrent and secure

If Done Has not been close,Err Method returns nil; If Done By close,Err Method will return Done By close Why

Two 、Context Use

stay Google, For functions that receive or send request classes , We require that Context Pass as the first parameter . such , Even for different teams Go Code can also work well .Context It's very convenient goroutine Timeout and cancellation control , And ensure the safe transmission of important data , Such as security credentials

context Package mainly provides two methods to create Context

  • context.Background()
  • context.TODO()

These two functions are aliases to each other , There is no difference , The official definition of :

  • context.Background Is the default value for the context , All other contexts should derive from it (Derived) come out
  • context.TODO() It should only be used when you are not sure which context to use

Created in these two ways context, Without any function , Its realization depends on context Provided by the package with Series

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{
    }) Context

A project on Context Use , Through these four derived functions , Form a Context Count . Each node of the tree can have any number of child nodes , There can be as many nodes as you want , Each child node depends on the parent node

[ Failed to transfer the external chain picture , The origin station may have anti-theft chain mechanism , It is suggested to save the pictures and upload them directly (img-SslcluBn-1656939722939)(./images/context-derive.png)]

2.1 WithValue Carrying data 、Value get data

Here is an open source project GVA As an example, the data initialization part of the code in , Deleted some judgment and data codes , Just keep context part

// InitDB  Create the database and initialize   The main entrance 
func (initDBService *InitDBService) InitDB(conf request.InitDB) (err error) {
    
	ctx := context.TODO()

	var initHandler TypedDBInitHandler
	
	initHandler = NewMysqlInitHandler()
	ctx = context.WithValue(ctx, "dbtype", "mysql")
	
	ctx, _ = initHandler.EnsureDB(ctx, &conf)
	
	db := ctx.Value("db").(*gorm.DB)
	global.GVA_DB = db

	if err = initHandler.WriteConfig(ctx); err != nil {
    
		return err
	}
	if err = initHandler.InitTables(ctx, initializers); err != nil {
    
		return err
	}
	if err = initHandler.InitData(ctx, initializers); err != nil {
    
		return err
	}

	return nil
}

// EnsureDB  Create the database and initialize  mysql
func (h MysqlInitHandler) EnsureDB(ctx context.Context, conf *request.InitDB) (next context.Context, err error) {
    
	if s, ok := ctx.Value("dbtype").(string); !ok || s != "mysql" {
    
		return ctx, ErrDBTypeMismatch
	}
	c := conf.ToMysqlConfig()
	next = context.WithValue(ctx, "config", c)
	next = context.WithValue(next, "db", db)
}


// WriteConfig mysql Write back configuration 
func (h MysqlInitHandler) WriteConfig(ctx context.Context) error {
    
	c, _ := ctx.Value("config").(config.Mysql)

	global.GVA_CONFIG.Mysql = c
	return global.GVA_VP.WriteConfig()
}

Here is based on context.TODO() Created a ctx, adopt context.WithValue take dbtype, config and db write in context, And then through context Tree passing , Any derived from context Can get these three information

In the code context The process :

  1. InitDB write in dbtype,EnsureDB adopt Value obtain dbtype Judge whether the database type is correct
  2. EnsureDB write in config and db Information
  3. WriteConfig obtain config Content is written back to the configuration file
  4. InitDB obtain db Information , Assign to global variable , obtain gorm.DB client

about withValue There are four precautions for the use of :

  • Not recommended context Values pass key parameters , The key parameters should be declared as shown , Should not be handled implicitly
  • carry value It's also keyvalue In the form of , for fear of context Because multiple packages are used at the same time context And bring conflict ,key Built in type is recommended
  • Get key value timing , We should start from the current context Search for , Not found will be from the father context Find the value corresponding to the key in until it is in a parent context Back in nil Or find the corresponding value
  • context In the data transferred keyvalue All are interface type , This type cannot be determined at compile time , So it's not very safe , So don't forget to ensure the robustness of the program when asserting types

2.2 WithCancel Cancel control

In daily business development, many meetings are held to complete a complex requirement goroutine To do something , This leads us to open multiple... In one request goroutine I really can't control them , And then we can use it withCancel To derive a context Pass to different goroutine in , When you want these goroutine Stop running , You can call cancel To cancel

The example here is the follow-up to the above InitTables and InitData part

func (h MysqlInitHandler) InitTables(ctx context.Context, inits initSlice) error {
    
	return createTables(ctx, inits)
}
// createTables  Create table ( Default  dbInitHandler.initTables  Behavior )
func createTables(ctx context.Context, inits initSlice) error {
    
	next, cancel := context.WithCancel(ctx)
	defer func(c func()) {
     c() }(cancel)
    return nil
}

func (h MysqlInitHandler) InitData(ctx context.Context, inits initSlice) error {
    
	next, cancel := context.WithCancel(ctx)
	defer func(c func()) {
     c() }(cancel)
    return nil
}

however GVA There are not many examples in this part of goroutine Of , More is to show context Context messaging

So cancel the control , Look at the next example to show more context control goroutine

func main()  {
    
    ctx,cancel := context.WithCancel(context.Background())
    go CancelText(ctx)
    time.Sleep(10*time.Second)
    cancel()
    time.Sleep(1*time.Second)
}

func CancelText(ctx context.Context)  {
    
    for range time.Tick(time.Second){
    
        select {
    
        case <- ctx.Done():
            fmt.Println("stop time")
            return
        default:
            fmt.Println("start time")
        }
    }
}

Use WithCancel Create one based on Background Of ctx; main Function main coroutine call CancelText Zixie Cheng , The sub process keeps printing start time, until ctx.Done() Successfully closed

The main process is 10s After execution cancel,CancelText The subprocess exits after detecting the cancellation signal

Reference resources

[1] Go Concurrency Patterns: Context
[2] Xiaobai can also understand context Bao explained in detail : From entry to mastery

原网站

版权声明
本文为[Heavy dust]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/188/202207062355469179.html