教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 golang 上下文_Golang中的上下文!

golang 上下文_Golang中的上下文!

发布时间:2021-12-18   编辑:jiaochengji.com
教程集为您提供golang 上下文,Golang中的上下文!等资源,欢迎您收藏本站,我们将为您提供最新的golang 上下文,Golang中的上下文!资源
<article style="font-size: 16px;">

golang 上下文

<h4> 重点 <span style="font-weight: bold;">(</span>Top highlight<span style="font-weight: bold;">)</span></h4>
<section>
<h2> 让我们来一些 <span style="font-weight: bold;">(</span>Let’s get some<span style="font-weight: bold;">)</span></h2>

Applications in golang use Contexts for controlling and managing very important aspects of reliable applications, such as cancellation and data sharing in concurrent programming. This may sound trivial but in reality, it’s not that so. The entry point for the contexts in golang is the <code>context</code> package. It is extremely useful and probably one of the most versatile packages of the entire language. If you haven’t come across anything dealing with contexts yet, you probably will very soon (or maybe you just didn’t pay much attention to it). The usage of context is so widespread that multiple other packages rely on it and assume you will do the same. It is definitely a key component on golang’s ecosystem.

Golang中的应用程序使用上下文来控制和管理可靠应用程序的非常重要的方面,例如并发编程中的取消和数据共享。 这听起来很琐碎,但实际上并非如此。 golang中<code>context</code>的入口点是<code>context</code>包。 它非常有用,并且可能是整个语言中功能最多的软件包之一。 如果您还没有遇到任何有关上下文的内容,那么您可能很快就会(或者也许您只是对此不太在意)。 上下文的用法是如此广泛,以至于其他多个软件包都依赖于上下文,并假设您将做同样的事情。 它绝对是golang生态系统中的关键组成部分。

Here’s the official documentation for the <code>context</code> package https://golang.org/pkg/context/. It’s really great and filled with practical examples. In an attempt to extend those, let’s have a look into things I have came across in real applications.

这是<code>context</code>包https://golang.org/pkg/context/的官方文档。 确实很棒,并有许多实际示例。 为了扩展这些内容,让我们看一下我在实际应用程序中遇到的事情。

<h2> 有价值的环境 <span style="font-weight: bold;">(</span>Context with value<span style="font-weight: bold;">)</span></h2>

One of the most common uses for contexts is to share data, or use request scoped values. When you have multiple functions and you want to share data between them, you can do so using contexts. The easiest way to do that is to use the function <code>context.WithValue</code>. This function creates a new context based on a parent context and adds a value to a given key. You can think about the internal implementation as if the context contained a <code>map</code> inside of it, so you can add and retrieve values by key. This is very powerful as it allows you to store any type of data inside the context. Here’s an example of adding and retrieving data with a context.

上下文最常见的用途之一是共享数据或使用请求范围的值。 当您具有多个功能并且想要在它们之间共享数据时,可以使用上下文来实现。 最简单的方法是使用<code>context.WithValue</code>函数。 此函数基于父上下文创建一个新上下文,并向给定键添加一个值。 你可以想想内部实现,就好像上下文包含一个<code>map</code>在它的内部,这样你就可以添加和键检索值。 这非常强大,因为它允许您在上下文中存储任何类型的数据。 这是一个使用上下文添加和检索数据的示例。

<figure style="display:block;text-align:center;"><figcaption> Adding and reading value with context </figcaption><figcaption> 通过上下文增加和读取价值 </figcaption></figure>

One important aspect of the design behind context package is that everything returns a new <code>context.Context</code> struct. This means that you have to remember to work with the returned value from operations and possibly override old contexts with new ones. This is a key design in immutability. If you want to know more about immutability in golang you can read this article I wrote about it.

上下文包背后的设计的一个重要方面是,所有内容都返回一个新的<code>context.Context</code>结构。 这意味着您必须记住要使用操作返回的值,并可能用新的上下文覆盖旧的上下文。 这是不变性的关键设计。 如果您想进一步了解golang的不变性,可以阅读我写的这篇文章 。

Using this technique you can pass along the <code>context.Context</code> to concurrent functions and as long as you properly manage the context you are passing on, it’s good way to share scoped values between those concurrent functions (meaning that each context will keep their own values on its scope). That’s exactly what <code>net/http</code> package does when handling HTTP requests. To elaborate on that let’s have a look into the next example.

使用这种技术,您可以将<code>context.Context</code>传递给并发函数,并且只要您正确管理要传递的上下文,这是在这些并发函数之间共享作用域值的好方法(这意味着每个上下文都将保留自己的值)其范围)。 这正是<code>net/http</code>程序包在处理HTTP请求时所做的。 为了对此进行详细说明,让我们看一下下一个示例。

<h2> 中间件 <span style="font-weight: bold;">(</span>Middlewares<span style="font-weight: bold;">)</span></h2>

A great example and use case for request scoped values is working with middlewares in web request handlers. The type <code>http.Request</code> contains a context which can carry scoped values throughout the HTTP pipeline. It is very common to see code where middlewares are added to the HTTP pipeline and the results of the middlewares are added to the <code>http.Request</code> context. This is a very useful technique as you can rely on something you know happened to in your pipeline already on later stages. This also enables you to use generic code to handle HTTP request, while respecting the scope where you want to share the data (instead of sharing data on global variables for example). Here’s an example of a middleware that leverages the request context.

请求范围值的一个很好的示例和用例是在Web请求处理程序中使用中间件。 类型<code>http.Request</code>包含一个上下文,该上下文可以在整个HTTP管道中携带范围值。 看到将中间件添加到HTTP管道,并将中间件的结果添加到<code>http.Request</code>上下文的代码是很常见的。 这是一项非常有用的技术,因为您可以依赖在后期阶段管道中已发生的事情。 这还使您能够使用通用代码来处理HTTP请求,同时遵守要共享数据的范围(例如,而不是共享全局变量的数据)。 这是一个利用请求上下文的中间件示例。

<figure style="display:block;text-align:center;"><figcaption> Middleware that adds a guid into the request context </figcaption><figcaption> 将GUID添加到请求上下文的中间件 </figcaption></figure>

If you want to understand middlewares better or just check more use cases for this technique check this article out.

如果您想更好地理解中间件,或者只是想了解更多使用这种技术的用例,请查看本文 。

<h2> 上下文取消 <span style="font-weight: bold;">(</span>Context Cancellation<span style="font-weight: bold;">)</span></h2>

Another very useful feature of context in golang is cancelling things that are related. This is very important when you want to propagate your cancellation. It’s a good practice to propagate the cancellation signal when you receive one. Let’s say you have a function where you start tens of goroutines. That main function waits for all goroutines to finish or a cancellation signal before proceeding. If you receive the cancellation signal you may want to propagate it to all your goroutines, so you don’t waste compute resources. If you share the same context among all goroutines you can easily do that.

golang中上下文的另一个非常有用的功能是取消相关的事物。 当您要传播取消消息时,这非常重要。 接收消除信号时,传播消除信号是一个好习惯。 假设您有一个函数,可以启动数十个goroutine。 该主要功能在继续执行之前会等待所有goroutine完成或发出取消信号。 如果您收到取消信号,则可能需要将其传播到所有goroutine,因此您不会浪费计算资源。 如果您在所有goroutine中共享相同的上下文,则可以轻松地做到这一点。

<mark>To create a context with cancellation you only have to call the function </mark><mark><code>context.WithCancel(ctx)</code></mark><mark> passing your context as parameter. This will return a new context and a cancel function. To cancel that context you only need to call the cancel function.</mark>

<mark> 要创建带有取消的上下文,您只需调用该函数 </mark><mark><code>context.WithCancel(ctx)</code> </mark><mark> 将您的上下文作为参数传递。 这将返回一个新的上下文和一个取消函数。 要取消该上下文,您只需要调用cancel函数。 </mark>

Here’s an example of a Hedged Request implementation with context cancellation. Just a quick recap about Hedged Requests: We fire a request to an external service, if the response doesn’t come back within our defined timeout, we issue a second request. When a response comes back, all other requests are cancelled.

这是带有上下文取消功能的对冲请求实现的示例。 简要回顾一下对冲的请求 :我们向外部服务发出请求,如果在定义的超时时间内仍未返回响应,我们将发出第二个请求。 当响应返回时,所有其他请求都被取消。

<figure style="display:block;text-align:center;"/>

Each request is fired in a separate goroutine. The context is passed to all requests that are fired. The only thing that is being done with the context is that it gets propagated to the HTTP client. This allows a graceful cancellation of the request and underlying connection when the <code>cancel</code> function is called. This is a very common patter for functions that accept a <code>context.Context</code> as argument, they either actively act on the context (like checking if it was cancelled) or they pass it to an underlying function that deals with it (in this case the <code>Do</code> function that receives the context through the <code>http.Request</code>).

每个请求都在单独的goroutine中触发。 上下文将传递到所有触发的请求。 上下文唯一要做的就是将其传播到HTTP客户端。 当调用<code>cancel</code>函数时,这可以优雅地取消请求和基础连接。 这对于接受功能的一个非常常见的图案<code>context.Context</code>作为参数,他们要么积极地作用于环境(如检查是否被取消),或者将它传递给底层函数,它的交易(在这种情况下, <code>Do</code>通过<code>http.Request</code>接收上下文的<code>http.Request</code> )。

<h2> 上下文超时 <span style="font-weight: bold;">(</span>Context Timeout<span style="font-weight: bold;">)</span></h2>

Timeouts are a really common pattern for making external requests, like querying a database or fetching data from another service either through HTTP or gRPC (both support contexts). Handling those scenarios is quite easy using the context package. All you have to do is call the function <code>context.WithTimeout(ctx, time)</code> passing your context and the actual timeout. Like this:

超时是发出外部请求的一种非常常见的模式,例如通过HTTP或gRPC(均支持上下文)查询数据库或从另一个服务获取数据。 使用上下文包处理这些场景非常容易。 您要做的就是调用函数<code>context.WithTimeout(ctx, time)</code>传递上下文和实际超时。 像这样:

<pre><code class="has">ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)</code></pre>

You still receive the cancel function in case you want to manually trigger that. It works the same way as a normal context cancellation.

如果您要手动触发该功能,您仍然会收到取消功能。 它的工作方式与普通上下文取消相同。

<blockquote>

It is a good practice to always defer the cancel function when it is available to avoid context leaking.

最好始终推迟使用取消功能以避免上下文泄漏。

</blockquote>

The behaviour for this case is very straightforward. In case the timeout is reached, the context is cancelled. Is case of a HTTP call, it works essentially the same as the example above.

这种情况的行为非常简单。 如果达到超时,则取消上下文。 如果是HTTP调用,则其工作原理与上面的示例基本相同。

<h2> gRPC <span style="font-weight: bold;">(</span>gRPC<span style="font-weight: bold;">)</span></h2>

Context is a fundamental piece of gRPC implementation in golang. It is used both to share data (what is called metadata) and to control flow, like cancelling a stream or request. These are two examples from my github repository.

上下文是golang中gRPC实现的基本组成部分。 它既可以用于共享数据(称为元数据 ),也可以用于控制流,例如取消流或请求。 这是我的github存储库中的两个示例。

Metadata:

元数据:

<figure style="display:block;text-align:center;"><figcaption> Server implementation receiving metadata </figcaption><figcaption> 服务器实现接收元数据 </figcaption></figure><figure style="display:block;text-align:center;"><figcaption> Client implementation sending metadata </figcaption><figcaption> 客户端实现发送元数据 </figcaption></figure>

Cancellation:

消除:

<figure style="display:block;text-align:center;"><figcaption> Server implementation handling context cancellation </figcaption><figcaption> 服务器实现处理上下文取消 </figcaption></figure><figure style="display:block;text-align:center;"><figcaption> Client implementation using timeout context cancellation </figcaption><figcaption> 使用超时上下文取消的客户端实现 </figcaption></figure><h2> 开放遥测 <span style="font-weight: bold;">(</span>OpenTelemetry<span style="font-weight: bold;">)</span></h2>

OpenTelemetry also relies heavily on context for what is called Context Propagation. That is a way to tied up requests happening in different systems. The way to implement that is to <code>Inject</code> span information into the context you are going to send as part of the protocol you are using (HTTP or gRPC, for instance). On the other service you need to <code>Extract</code> the span information out of the context. I wrote about OpenTelemetry in two articles, you can find the part 1 here, and part 2 here. There you can find more information about OpenTelemetry as well as examples using both gRPC and HTTP.

OpenTelemetry还严重依赖于上下文进行所谓的Context Propagation 。 这是捆绑不同系统中发生的请求的一种方法。 实现方法是将<code>Inject</code>信息注入到要作为所使用协议(例如HTTP或gRPC)的一部分发送的上下文中。 在其他服务上,您需要从上下文中<code>Extract</code>跨度信息。 我在两篇文章中谈到了OpenTelemetry,您可以在这里找到第1部分,在这里找到第2部分 。 在这里,您可以找到有关OpenTelemetry的更多信息以及同时使用gRPC和HTTP的示例。

<h2> 最后的想法 <span style="font-weight: bold;">(</span>Final Thoughts<span style="font-weight: bold;">)</span></h2>

Contexts are used as part of golang basic features. Thus, it is very important to understand and know how to work with them. The <code>context</code> package provides a very easy and lightweight API to interact with this key component. Another important thing to call out about the <code>context.Context</code> is that it can be used for multiple things. We covered a lot of scenarios in this article, in some of them a single context could be used to control and carry cancellation signals as well as to carry scoped values. This makes the context a very important and powerful tool to create reliable and simple code.

上下文被用作golang基本功能的一部分。 因此,了解并知道如何与他们合作非常重要。 <code>context</code>包提供了一个非常简单轻便的API来与该关键组件进行交互。 关于<code>context.Context</code>另一件重要的事情是<code>context.Context</code> ,它可以用于多种事物。 我们在本文中介绍了许多场景,在某些场景中,可以使用单个上下文来控制和传递抵消信号以及传递范围值。 这使上下文成为创建可靠且简单的代码的非常重要且功能强大的工具。

</section>
<blockquote>

翻译自: https://levelup.gitconnected.com/context-in-golang-98908f042a57

</blockquote>

golang 上下文

</article> 到此这篇关于“golang 上下文_Golang中的上下文!”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
golang key map 所有_golang推断map中指定key是不是存在_后端开发
golang key map 所有_golang之map
golang 初始化并赋值_golang语言中map的初始化及使用示范
golang 函数传多个参数_Golang中的参数传递示例详解
golang 字符串分割_Golang 微服务教程(四)
golang 动态生成函数_GoLang的优点和缺点
golang https 全局代理_Golang 调度器
golang 所有进程休眠_Golang中Goroutine的调度流程
golang把数字变字符串_golang高频面试题:翻转含有中文、数字、英文字母的字符串...
golang map 锁_Golang线程安全的map

[关闭]
~ ~