Context is a unique design of the Go language. It is rarely seen in other programming languages.

Context provides the ability to exit signal notification and metadata transfer between multiple Goroutines of the same task.

So if you don’t use Context, you can’t do signal notifications and metadata between goroutines in Go? The answer is: yes in simple scenarios, but not in multilevel Goroutine control.

Let’s take an example to understand the above statement

If there are multiple tasks in the main coroutine, the main coroutine has timeout control over these tasks. Task 1 has multiple subtasks, and task 1 also has its own timeout control over these subtasks. Therefore, these subtasks need to sense both the cancellation signal of the main coroutine and the cancellation signal of task 1.

The deeper the goroutine level of the task, the harder it is to do your own exit signal awareness and metadata sharing.

So we need an elegant solution to implement such a mechanism:

  • [Fixed] After the upper level mission is cancelled, all lower level missions are cancelled.
  • If a task at a middle level is cancelled, only the tasks at the lower level of the current task will be cancelled, without affecting the tasks at the upper level and other tasks at the same level.
  • Some task metadata can be shared between Goroutine threads safely

Go officially introduced Context in version 1.7 to implement the mechanism described above.

The Go Context package provides the interface definition and type implementation of the context. Let me use a class diagram to describe the interface and type provided by the context.

We can get this information from the class diagram above

  • In addition to the Context interface, we define an interface called canceler that implements the canceler Context of type.

  • EmptyCtx has no property and cannot do anything.

  • ValueCtx can carry only one key-value pair attached to the upper-level Context.

  • TimerCtx descends from cancelCtx, both of which are Context cancelCtx.

  • Except for emptyCtx, all other types of Context are attached to the parent Context

After looking at this class diagram, you might be asking how does Context allow tasks to be passed between metadata? After all, a valueCtx carries only one key-value pair. It implements a Value method that looks up the Value of the specified key throughout the Context link until it goes back to the root Context.

By looking at the diagram of the key-value pairs carried by the Context, we can see that the root node of the Context link is an emptyCtx. This is why emptyCtx does nothing. It is used as the root node.

Each time you want to add a key-value pair to the Context link, you need to create a valueCtx key-value pair based on the previous Context. It can only be added but cannot be modified. Reading the key value of the Context is an idempotent operation. So Context implements thread-safe data sharing without locking, without affecting performance.

Context cancels all lower-level tasks when the upper-level task is cancelled. Context cancels all lower-level tasks when the upper-level task is cancelled. Context cancels all lower-level tasks when the upper-level task is cancelled.

CancelCtx and timerCtx are collectively referred to as cancelCtx contexts below, and will also be represented by the cancelCtx symbol in the schematic.

First of all, when creating a Context with cancellation, you should create it on the basis of the parent Context node to maintain the continuity of the entire Context link. In addition, it will find the previous Context with cancellation in the Context link and add itself to its children list.

In addition to the parent Context being directly associated with it, the cancelable Context will also be associated with its child cancelable Context by maintaining the children property it carries.

The diagram above gives us a better understanding of the possible panorama of the whole Context link.

For those of you looking at the source code, focus on calls to propagateCancel with WithCancel and WithDeadline

A propagateCancel finds a cancelable Context in the ancestor Context node, propagateCancel maintains itself in the children attribute of the ancestor

Through this structure design, if you want to cancel a cancelCtx on the whole task link, you can cancel both yourself and all the cancelCtx at the lower level without affecting other nodes at the higher level and at the same level.

Now let’s go back to the first example, and once we have the Context, what does our task look like?

We make each goroutine carry a Context, and the goroutine that does the subtask will get a signal to stop running if it is listening for cancelCtx, The Context is used to cancel the control of the upper goroutine over the lower goroutine.

In the case of different levels of goroutine cancellation conditions, the code only needs to listen to the Context passed to the Goroutine to do so, eliminating the need to listen for multiple signals.

For Context usage recommendations, Go officially mentions the following:

  1. Don’t stuff the Context into the structure. The function takes the Context type directly as the first argument, and is usually named CTX.
  2. Don’t pass a nil context to a function. If you really don’t know what to pass, the library’s TODO method has an emptyCtx ready for you.
  3. Don’t stuff the context with a type that should be a function parameter. Context should store data that is shared in Goroutine, such as Server information.

The first part of the first point is a bit of a stretch for me, as the official NET/HTTP package puts the Context inside the Request structure, but there are other points that need to be noted.

Ok, today is a day of unwrapped source code. I’m showing you the design concept of Context and its important role in Go in plain English and a few illustrations. If you like this form, please give it a thumbs up and check it out, thanks for your support.

If you want to see the source code of the context, you should note that the code described in the article is version 1.9, later several versions of the source code of the context has been tweaked, but it does not affect the understanding of the entire implementation principle of the context.

That’s all for today’s article, please give me a thumbs up if you like my article, AND I will share what I have learned and seen and first-hand experience through technical articles every week. Thank you for your support. Wechat search attention to the public number – bi network management nagging every week to teach you an advanced knowledge.