当前位置:网站首页>Understand the context in go language in an article
Understand the context in go language in an article
2022-07-04 15:15:00 【1024 questions】
0 Pre knowledge sync.WaitGroup
1 brief introduction
2 context.Context introduce
3 context Other commonly used functions of the package
3.1 context.Background and context.TODO
3.2 context.WithCancel and
3.3 context.WithTimeout
3.4 context.WithDeadline
3.5 context.WithValue
4 example : Request browser timeout
5 Context Where are the bags used
6 Summary
0 Pre knowledge sync.WaitGroupsync.WaitGroup Is to wait for the end of a group of collaborative processes . It implements a structure similar to task queue , You can add tasks to the queue , Remove the task from the queue after the task is completed , If all the tasks in the queue are not completed , The queue triggers a block to prevent the program from continuing . sync.WaitGroup Only 3 A way ,Add(),Done(),Wait() .
among Done() yes Add(-1) Another name for , Use Add() Add count ,Done() Subtract a count , Count is not 0, Blocking Wait() Operation of .
Example :
package mainimport ( "fmt" "sync" "time")var group sync.WaitGroupfunc sayHello() { for i := 0; i < 5; i++ { fmt.Println("hello......") time.Sleep(time.Second) } // Thread end -1 group.Done()}func sayHi() { // Thread end -1 defer group.Done() for i := 0; i < 5; i++ { fmt.Println("hi......") time.Sleep(time.Second) }}func main() { //+2 group.Add(2) fmt.Println("main Blocking ...") go sayHello() fmt.Println("main Persistent obstruction ...") go sayHi() // Thread waiting group.Wait() fmt.Println("main It seems that the jam is over ...")}
effect :
stay Go Server , Each incoming request is in its own goroutine In dealing with . Request handlers usually start additional goroutine To access the backend , For example, databases and RPC service . A group of that processes requests goroutine You usually need to access request specific values , For example, the identity of the end user 、 Authorization token and request deadline . When the request is cancelled or exceeded , Handle all of the requests goroutine We should all quit quickly , So that systems can recycle any resources they are using .
So , Developed a context
package , The value of the requested range can be easily 、 Cancellation signal and deadline span API The boundary is passed to all involved in processing the request goroutine.
Context Carry a deadline 、 A cancellation signal and other jumps API Boundary value . Contextual methods can be used by multiple gor Routine calls .
Incoming requests to the server should create a context , Outgoing calls to the server should accept a context . The function call chain between them must propagate Context, You can choose to replace it with WithCancel、WithDeadline、WithTimeout or WithValue Created derivation Context. When a context is cancelled , All contexts derived from it are also cancelled .
WithCancel、WithDeadline and WithTimeout Function adoption Context( Father ) And returns the derived Context( Son ) and CancelFunc. call CancelFunc Will cancel the subitems and their subitems , Delete the reference of parent item to child item , And stop any associated timers . call CancelFunc Failure will leak children and their children , Until the parent item is canceled or the timer is triggered .go vet The tool checks whether CancelFuncs.
Procedures that use context should follow the following rules , To maintain consistent interfaces across packages , And enable static analysis tools to check context propagation :
Don't store context in structure type ; contrary , take Context Explicitly pass it to every function that needs it .
Context It should be the first parameter , Usually named ctx:
func DoSomething(ctx context.Context, arg Arg) error { // ... Use ctx ... }
Even if the function allows , Don't pass on nil Context . If you're not sure which one to use Context, Please deliver context.TODO.
Use context values only for transfer processes and API Request scope data , It is not used to pass optional parameters to functions .
same Context Can be passed to in different goroutine Functions running in ; Context for multiple goroutine It's safe to use at the same time .
// The context carries the deadline 、 The values of the cancellation signal and request range are API The boundaries of . Its method is safe to use multiple at the same time goroutine.type Context interface { // Done Returns a channel closed when the context is canceled or timed out . Done() <-chan struct{} // Err It means that Done Why cancel this context after the channel is closed . Err() error // Deadline Returns the time when the context will be canceled ( If any ). Deadline() (deadline time.Time, ok bool) // Value Return and key Related values , If not, return nil. Value(key interface{}) interface{}}
The Done
Method returns a channel , This channel acts as a cancellation signal representing the function of operation Context
: When the channel is closed , Functions should give up their work and return .
The Err
Method returns an error , instructions Context
Reason for cancellation .
One Context
For multiple goroutine It's safe to use at the same time . Code can pass a single Context
Give any number of goroutines And cancel it Context
To all goroutine Signal .
The Deadline
Methods allow functions to determine whether they should start working , You can also use the deadline to set I/O Timeout for operation .
Value
Allows a Context
Carry the data of the requested range . The data must be secure , In order to more goroutine Use at the same time .
Background Any Context The root of the tree , It will never be cancelled :
//Background Returns an empty Context. It will never be cancelled , There is no deadline , There is no value . Background Usually used for main、init and tests, And as the top-level context of the incoming request . func Background() Context
Pass to a function method Context When , Do not pass nil, If you don't know what to deliver , Just use context.TODO()
3.2 context.WithCancel andWithCancelt Returns derived Context value , You can compare with your father Context Cancel faster . When the request handler returns , Usually, the content. When using multiple copies ,WithCancel It is also useful for cancelling redundant requests .
// WithCancel Return a copy of the parent process , Of the parent process Done The channel is closed as soon as possible . close Done Or call cancel.func WithCancel(parent Context) (ctx Context, cancel CancelFunc)// CancelFunc Cancel a context .type CancelFunc func()
Example :
package mainimport ( "context" "fmt")func play(ctx context.Context) <-chan int { dist := make(chan int) n := 1 // Anonymous functions towards dist Add elements to go func() { for { select { //ctx This... Will not be executed when it is empty case <-ctx.Done(): return // return End this goroutine, Prevent leakage // towards dist Add elements to case dist <- n: n++ } } }() return dist}func main() { // Return empty context ctx, cancel := context.WithCancel(context.Background()) defer cancel() // call cancel for n := range play(ctx) { fmt.Println(n) if n == 5 { break } }}
Expand :go in select Usage of
```select The usage and switch The language is very similar , from select Start a new selection block , Each selection is made by case To describe . And switch Statement than , select There are more restrictions , One of the biggest restrictions is that each case There must be a IO operation , The general structure is as follows :``` goselect { case <-chan1: // If chan1 Successfully read the data , Then go ahead with the case Processing statements case chan2 <- 1: // If we succeed in chan2 Write data , Then go ahead with the case Processing statements default: // If none of the above works , entering default Processing flow }``` In a select In the sentence ,Go The language evaluates each statement sent and received from beginning to end in order . If any of these statements can continue ( That is, it is not blocked ), Then choose any one of those executable statements to use . If no statement can be executed ( That is, all channels are blocked ), So there are two possibilities :- If given default sentence , Then it will carry out default sentence , At the same time, the execution of the program will start from select Restore... In the statement after the statement .- without default sentence , that select The statement will be blocked , Until at least one communication can go on .```
3.3 context.WithTimeoutWithTimeout Returns derived Context value ,WithTimeout Used to set the deadline for requests to the back-end server :
//WithTimeout Return a copy of the parent process , Of the parent process Done Parents whose channels were immediately closed . close “ complete ”、 call “ Cancel ” Or timeout ends . new //Context Of Deadline It's faster now +timeout And father's Deadline, If anything . If the timer is still running , be cancel Function to release its resources .func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)// CancelFunc Cancel a context .type CancelFunc func()
Example :
package mainimport ( "context" "fmt" "sync" "time")var wg sync.WaitGroupfunc worker(ctx context.Context) { LOOP: for { fmt.Println("db connecting ...") time.Sleep(time.Millisecond * 10) // Suppose it takes time to connect to the database normally 10 millisecond select { case <-ctx.Done(): // 50 Called automatically in milliseconds break LOOP default: } } fmt.Println("worker done!") wg.Done()}func main() { // Set up a 50 A millisecond timeout ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50) wg.Add(1) go worker(ctx) time.Sleep(time.Second * 5) cancel() // Notifier goroutine end wg.Wait() fmt.Println("over")}
Execution results :
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) { if parent == nil { panic("cannot create context from nil parent") } if cur, ok := parent.Deadline(); ok && cur.Before(d) { // The current deadline is already ahead of the new deadline return WithCancel(parent) } c := &timerCtx{ cancelCtx: newCancelCtx(parent), deadline: d, } propagateCancel(parent, c) dur := time.Until(d) if dur <= 0 { c.cancel(true, DeadlineExceeded) // The deadline has passed return c, func() { c.cancel(false, Canceled) } } c.mu.Lock() defer c.mu.Unlock() if c.err == nil { c.timer = time.AfterFunc(dur, func() { c.cancel(true, DeadlineExceeded) }) } return c, func() { c.cancel(true, Canceled) }}
Example :
package mainimport ( "context" "fmt" "time")func main() { d := time.Now().Add(500 * time.Millisecond) ctx, cancel := context.WithDeadline(context.Background(), d) // Even though ctx Will expire , But in any case it's called cancel Functions are good practices . // If you don't do that , It may make the context and its parent class live longer than necessary . defer cancel() select { case <-time.After(1 * time.Second): fmt.Println("over") case <-ctx.Done(): fmt.Println(ctx.Err()) }}
Execution results :
WithValue Provides a way to compare the value of the request range with Context The method of Association :
//WithValue Return a copy of the parent element , Its Value Method returns val for key.func WithValue(parent Context, key interface{}, val interface{}) Context
Learn how to use context The best way to package is through a working example .
Example :
package mainimport ( "context" "fmt" "sync" "time")type TraceCode stringvar wg sync.WaitGroupfunc worker(ctx context.Context) { key := TraceCode("KEY_CODE") traceCode, ok := ctx.Value(key).(string) // In the child goroutine In order to get trace code if !ok { fmt.Println("invalid trace code") } LOOP: for { fmt.Printf("worker,code:%s\n", traceCode) time.Sleep(time.Millisecond * 10) // Suppose it takes time to connect to the database normally 10 millisecond select { case <-ctx.Done(): // 50 Called automatically in milliseconds break LOOP default: } } fmt.Println("worker is over!") wg.Done()}func main() { // Set up a 50 A millisecond timeout ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50) // Set in the entrance of the system trace code Pass it on to the subsequent startup goroutine Realize log data aggregation ctx = context.WithValue(ctx, TraceCode("KEY_CODE"), "12512312234") wg.Add(1) go worker(ctx) time.Sleep(time.Second * 5) cancel() // Notifier goroutine end wg.Wait() fmt.Println("over")}
Execution results :
server End :
package mainimport ( "fmt" "math/rand" "net/http" "time")// server End , Random slow response func indexHandler(w http.ResponseWriter, r *http.Request) { number := rand.Intn(2) if number == 0 { time.Sleep(time.Second * 10) // Time consuming 10 Slow response in seconds fmt.Fprintf(w, "slow response") return } fmt.Fprint(w, "quick response")}func main() { http.HandleFunc("/", indexHandler) err := http.ListenAndServe(":9999", nil) if err != nil { panic(err) }}
client End :
package mainimport ( "context" "fmt" "io/ioutil" "net/http" "sync" "time")// client type respData struct { resp *http.Response err error}func doCall(ctx context.Context) { // http A long connection transport := http.Transport{DisableKeepAlives: true} client := http.Client{Transport: &transport} respChan := make(chan *respData, 1) req, err := http.NewRequest("GET", "http://127.0.0.1:9999/", nil) if err != nil { fmt.Println(err) return } req = req.WithContext(ctx) // Use the... With timeout ctx Create a new client request var wg sync.WaitGroup wg.Add(1) defer wg.Wait() go func() { resp, err := client.Do(req) fmt.Printf("resp:%v, err:%v\n", resp, err) rd := &respData{ resp: resp, err: err, } respChan <- rd wg.Done() }() select { case <-ctx.Done(): fmt.Println("timeout...") case result := <-respChan: fmt.Println("success....") if result.err != nil { fmt.Printf("err:%v\n", result.err) return } defer result.resp.Body.Close() data, _ := ioutil.ReadAll(result.resp.Body) fmt.Printf("resp:%v\n", string(data)) }}func main() { // Define a 100 A millisecond timeout ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100) defer cancel() // call cancel Releaser goroutine resources doCall(ctx)}
5 Context Where are the bags used Many server frameworks provide packages and types for hosting request scope values . We can define “Context” New implementation of interface , The code and needs of using the existing framework “Context” Build a bridge between the codes of parameters .
6 SummaryIn Google , requirement Go The programmer will “Context” Parameters are passed as the first parameter of each function on the call path between incoming and outgoing requests . This allows many different teams to develop Go The code can interoperate well . It provides simple control over timeouts and cancellations , And ensure that key values such as security credentials can be transmitted correctly Go Program .
Want to build on “Context” The server framework on should provide “Context” To connect their packages to those that need “Context” Package of parameters . then , Their client libraries will accept “Context”. By establishing a common interface for requesting scope data and cancellation ,“ Context ” Make it easier for package developers to share code that creates scalable services .
This is about an article to understand Go In language Context This is the end of the article , More about Go Context Please search the previous articles of software development network or continue to browse the relevant articles below. I hope you will support software development network more in the future !
边栏推荐
- Helix Swarm中文包发布,Perforce进一步提升中国用户体验
- Go zero micro service practical series (IX. ultimate optimization of seckill performance)
- Redis哨兵模式实现一主二从三哨兵
- 干货 | fMRI标准报告指南新鲜出炉啦,快来涨知识吧
- Korean AI team plagiarizes shock academia! One tutor with 51 students, or plagiarism recidivist
- unity update 协程_Unity 协程的原理
- 怎么判断外盘期货平台正规,资金安全?
- 进制形式
- Usage of database functions "recommended collection"
- go-zero微服务实战系列(九、极致优化秒杀性能)
猜你喜欢
对话龙智高级咨询顾问、Atlassian认证专家叶燕秀:Atlassian产品进入后Server时代,中国用户应当何去何从?
Redis 發布和訂閱
[local differential privacy and random response code implementation] differential privacy code implementation series (13)
力扣刷题01(反转链表+滑动窗口+LRU缓存机制)
Guitar Pro 8win10最新版吉他学习 / 打谱 / 创作
智能客服赛道:网易七鱼、微洱科技打法迥异
MP3是如何诞生的?
暑期复习,一定要避免踩这些坑!
Redis publier et s'abonner
音视频技术开发周刊 | 252
随机推荐
IO流:节点流和处理流详细归纳。
Numpy notes
What are the concepts of union, intersection, difference and complement?
UFO: Microsoft scholars have proposed a unified transformer for visual language representation learning to achieve SOTA performance on multiple multimodal tasks
Width and alignment
%S format character
Partial modification - progressive development
這幾年爆火的智能物聯網(AIoT),到底前景如何?
Decimal, exponential
Quelles sont les perspectives de l'Internet intelligent des objets (aiot) qui a explosé ces dernières années?
进制乱炖
Five minutes per day machine learning: use gradient descent to complete the fitting of multi feature linear regression model
Analysis of nearly 100 million dollars stolen and horizon cross chain bridge attacked
PLC Analog input analog conversion FC s_ ITR (CoDeSys platform)
Unity脚本API—Transform 变换
每周招聘|高级DBA年薪49+,机会越多,成功越近!
Implementation of web chat room
The per capita savings of major cities in China have been released. Have you reached the standard?
flutter 报错 No MediaQuery widget ancestor found.
C1 certification learning notes 3 -- Web Foundation