当前位置: 首页 > news >正文

浅析Golang的Context

文章目录

      • 1. 简介
      • 2. 常见用法
        • 2.1 控制goroutine的生命周期(cancel)
        • 2.2 传递超时(Timeout)信息
        • 2.3 传递截止时间(Deadline)
        • 2.4 传递请求范围内的全局数据 (value)
      • 3 特点
        • 3.1 上下文的不可变性
        • 3.2 链式传递
        • 3.3 超时和截止时间
        • 3.4 多级取消机制
        • 3.5 context.Value() 传递全局数据
        • 3.6 context 线程安全
        • 3.7 层次化的取消信号传播
      • 4 底层实现原理
        • 4.1 Context接口
        • 4.2 emptyCtx类
        • 4.3 cancelCtx类
        • 4.4 timerCtx类
        • 4.5 valueCtx类

1. 简介

在 Go 语言中,context 包主要用于在 并发编程 中控制和管理 goroutine 的生命周期。它提供了一种机制,可以通过传递 context.Context 来协调多个 goroutine,特别是在需要取消操作超时控制传递共享数据时。

2. 常见用法

2.1 控制goroutine的生命周期(cancel)

context 允许父 goroutine 可以通知子 goroutine 停止工作。例如,当你在 HTTP 服务器中处理一个请求时,如果客户端关闭了连接,你可能不再需要继续处理这个请求。通过 context,你可以在主流程中取消子流程(即 goroutine),避免不必要的资源消耗。

ctx, cancel := context.WithCancel(context.Background())
go func() {select {case <-ctx.Done():// 接收到取消信号,停止工作fmt.Println("Goroutine canceled")}
}()
// 取消操作
cancel()
2.2 传递超时(Timeout)信息

context 还可以传递一个超时时间,允许操作在指定时间后自动停止。这对于需要限定时间完成的操作(如数据库查询、API 调用)非常有用。

ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer cancel()select {
case <-time.After(time.Second * 1):fmt.Println("Operation completed within timeout")
case <-ctx.Done():fmt.Println("Operation timed out")
}
2.3 传递截止时间(Deadline)

context 可以包含一个截止时间(Deadline),这是在某个具体的时间点之后,所有的操作都应该停止。与超时类似,但它使用绝对时间而不是相对时间 。

deadline := time.Now().Add(time.Second * 5)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()select {
case <-time.After(time.Second * 6):fmt.Println("Operation completed")
case <-ctx.Done():fmt.Println("Deadline exceeded")
}
2.4 传递请求范围内的全局数据 (value)

context 还可以携带一些全局数据,虽然 context 设计的初衷并不是为了数据传递,但在一些场景下,利用 context 传递与请求上下文相关的信息是很常见的做法。例如,在 Web 服务中传递用户认证信息、跟踪请求 ID 等。

package mainimport ("context""fmt"
)// 创建一个 key 类型,用于在 context 中存储和检索数据
type key stringconst userIDKey key = "userID"// 传递用户 ID 的函数
func processRequest(ctx context.Context) {// 从 context 中取出用户 IDuserID := ctx.Value(userIDKey)if userID != nil {fmt.Println("User ID found in context:", userID)} else {fmt.Println("No User ID found in context")}
}func main() {// 创建一个带有用户 ID 的 contextctx := context.WithValue(context.Background(), userIDKey, "12345")// 传递带有用户 ID 的 contextprocessRequest(ctx)// 调用时没有用户 IDprocessRequest(context.Background())
}

3 特点

3.1 上下文的不可变性

context 是不可变的。一旦创建了一个 context,你不能修改它。每次你想要添加新的值、超时或取消机制时,都会创建一个新的子 context。这有助于保持 context 的并发安全,确保多个 goroutine 可以共享同一个 context 而不发生数据竞争。

例如,使用 context.WithValue 添加键值对时,实际上是创建了一个新的 context,旧的 context 保持不变。

parentCtx := context.Background()
childCtx := context.WithValue(parentCtx, "key", "value")
3.2 链式传递

context 是链式传递的。你可以从一个父 context 创建多个子 context,并且这些子 context 可以继续创建它们的子 context。这种设计允许你在复杂的程序中,管理多个 context,并且可以确保每个子 context 都能够追溯到其父 context

例如,当你调用 context.WithCancelcontext.WithTimeout 时,都会基于父 context 创建新的子 context

3.3 超时和截止时间

context 允许你为操作设置 超时时间截止时间。通过 context.WithTimeoutcontext.WithDeadline,你可以确保某些操作在指定时间内完成,否则自动取消。这对于网络请求、数据库查询等可能需要限制执行时间的操作非常有用。

  • context.WithTimeout:为上下文设置相对的超时时间。例如,在 5 秒后自动取消。
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
  • context.WithDeadline:为上下文设置绝对的截止时间。例如,在某个具体的时间点后取消。
deadline := time.Now().Add(10 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), deadline)
defer cancel()

在这两种情况下,一旦时间到了,ctx.Done() 通道会关闭,所有使用这个 context 的操作都会被取消。

3.4 多级取消机制

除了父 context 取消时会取消所有子 context 外,子 context 也可以通过独立的取消机制取消自己。例如,如果你为某个子 context 设置了独立的超时或调用了它的 cancel 函数,子 context 会取消,而其他的兄弟 context 或父 context 不受影响。

parentCtx, parentCancel := context.WithCancel(context.Background())
childCtx, childCancel := context.WithTimeout(parentCtx, 2*time.Second)go func() {<-childCtx.Done()fmt.Println("Child context cancelled")
}()time.Sleep(3 * time.Second)
parentCancel() // 取消父 context

在这个例子中,childCtx 会因为超时先被取消,而 parentCtx 只有在调用 parentCancel() 后才会取消。

3.5 context.Value() 传递全局数据

虽然 context 的设计主要是用于控制 goroutine 的生命周期,但它也可以通过 context.WithValue 传递少量的全局数据(键值对)。常见的使用场景包括在请求链路中传递用户认证信息、请求 ID 等。

注意:

  • context.Value() 传递的数据应该是与请求相关的少量数据,而不应当被滥用为数据存储机制。
  • 使用自定义的键类型(如 type key string)可以避免键冲突。
type key string
ctx := context.WithValue(context.Background(), key("userID"), "12345")
userID := ctx.Value(key("userID"))
fmt.Println("User ID:", userID)
3.6 context 线程安全

context 是设计为并发安全的。你可以将同一个 context 实例传递给多个 goroutine,而不需要担心数据竞争或同步问题。因为 context 的状态(如取消、超时)通过不可变的方式和通道传播,它天然支持并发。

func worker(ctx context.Context, id int) {select {case <-time.After(3 * time.Second):fmt.Printf("Worker %d done\n", id)case <-ctx.Done():fmt.Printf("Worker %d cancelled\n", id)}
}func main() {ctx, cancel := context.WithCancel(context.Background())for i := 1; i <= 3; i++ {go worker(ctx, i)}time.Sleep(1 * time.Second)cancel() // 取消所有子 goroutinetime.Sleep(4 * time.Second)
}
3.7 层次化的取消信号传播

context 结构中,当父 context 被取消时,所有子 context 会自动取消,这是一种层次化的取消信号传播机制。这可以帮助你在复杂系统中控制多个 goroutine 的生命周期。例如,在 Web 服务中,当用户取消请求时,所有与该请求相关的操作都应该立即停止。

context 被取消时,context.Err() 会返回具体的错误类型:

  • context.Canceled:表示上下文被显式取消(例如,调用了 cancel())。
  • context.DeadlineExceeded:表示上下文超时或截止时间已过。

4 底层实现原理

主要通过解析context的源码来剖析第三节中各个特点的实现机理。

4.1 Context接口
type Context interface {Deadline() (deadline time.Time, ok bool)Done() <-chan struct{}Err() errorValue(key any) any
}

这是context最核心的一个接口,定义了Context接口,包含了四个方法,其他结构体只要实现了这四个方法就实现了该接口。四个方法的功能分别是:

  • Deadline() (deadline time.Time, ok bool):Deadline 方法返回一个时间(time.Time),表示在这个上下文下执行的任务应该取消的截止时间。通常用在需要在某个时间点前完成的任务中。如果 context 没有设置任何截止时间,Deadline() 的返回值中,ok 会是 false。这意味着当前 context 没有时间限制,因此任务可以无限期地运行,除非被手动取消。对 Deadline() 的连续调用会返回相同的结果。
  • Done() <-chan struct{}:Done() 方法返回一个通道,用于通知 goroutine 某个 context 关联的任务应该被取消。Done() 返回一个通道(chan struct{}),这个通道在 context 关联的工作需要被取消时会关闭。你可以通过监听这个通道来决定是否继续执行某个操作。
  • Err() error:Err() 方法用于返回 context 的取消原因,尤其在 Done() 通道关闭之后,它提供了上下文取消的具体原因。如果 Done() 通道还没有关闭(即 context 没有被取消或超时),调用 Err() 方法将返回 nil。如果 Done() 通道已经关闭,Err() 方法会返回一个非空的错误(error),这个错误解释了为什么 context 被取消。(1) 如果 context 是由于调用 cancel() 函数而被取消的,Err() 将返回一个 context.Canceled 错误。这表明操作是手动取消的。 (2) 如果 context 是因为超时或截止时间到达而被取消的,Err() 将返回一个 context.DeadlineExceeded 错误。这表明操作是因为超时被取消的。
  • Value(key any) any:Value() 方法根据传入的键(key),返回与该键相关联的值。如果该键没有与任何值相关联,则返回 nil。 键的类型可以是支持相等性判断的任何类型(通常是简单的标识符类型)。为了避免不同包之间的键冲突,应该将键定义为未导出类型(即,首字母小写的类型)。
4.2 emptyCtx类

emptyCtx 是一种特殊的上下文,它永远不会被取消、没有任何关联的值,也没有截止时间。它是 context.Background()context.TODO() 的基础类型。

type emptyCtx struct{}func (emptyCtx) Deadline() (deadline time.Time, ok bool) {return
}func (emptyCtx) Done() <-chan struct{} {return nil
}func (emptyCtx) Err() error {return nil
}func (emptyCtx) Value(key any) any {return nil
}

context.Background()context.TODO()

func Background() Context {return backgroundCtx{}
}func TODO() Context {return todoCtx{}
}type backgroundCtx struct{ emptyCtx }func (backgroundCtx) String() string {return "context.Background"
}type todoCtx struct{ emptyCtx }func (todoCtx) String() string {return "context.TODO"
}

context.Background():这是 Go 程序中通常用作根上下文的上下文。它一般用于顶层的 context,例如在启动 goroutine、处理请求、初始化程序时使用。由于它基于 emptyCtx,所以它不会被取消、没有值或截止时间。

ctx := context.Background()

context.TODO()TODO() 通常用于代码还在编写过程中,开发者不确定应该使用哪种 context 的场景下。它是一个临时的占位符,表示将来会替换为合适的上下文。和 Background() 一样,TODO() 也是基于 emptyCtx,没有取消、值或截止时间。

ctx := context.TODO()
4.3 cancelCtx类
type cancelCtx struct {Contextmu       sync.Mutex            // protects following fieldsdone     atomic.Value          // of chan struct{}, created lazily, closed by first cancel callchildren map[canceler]struct{} // set to nil by the first cancel callerr      error                 // set to non-nil by the first cancel callcause    error                 // set to non-nil by the first cancel call
}// A canceler is a context type that can be canceled directly. The
// implementations are *cancelCtx and *timerCtx.
type canceler interface {cancel(removeFromParent bool, err, cause error)Done() <-chan struct{}
}

cancelCtx 是可以被取消的,当 cancelCtx 被取消时,它会自动取消所有实现了 canceler 接口的子上下文。子上下文需要实现 canceler 接口,canceler 接口通常会有一个 cancel() 方法,用于执行取消操作。一旦父上下文的 cancel() 被调用,父上下文会遍历所有子上下文,调用它们的 cancel() 方法,将取消信号逐层向下传递。

func (c *cancelCtx) Value(key any) any {if key == &cancelCtxKey {return c}return value(c.Context, key)
}func (c *cancelCtx) Done() <-chan struct{} {d := c.done.Load()if d != nil {return d.(chan struct{})}c.mu.Lock()defer c.mu.Unlock()d = c.done.Load()if d == nil {d = make(chan struct{})c.done.Store(d)}return d.(chan struct{})
}func (c *cancelCtx) Err() error {c.mu.Lock()err := c.errc.mu.Unlock()return err
}
  • func (c *cancelCtx) Value(key any) any:如果 key 与特定的 cancelCtxKey 相等,则返回当前 cancelCtx 实例本身;否则,调用嵌套的父上下文的 Value 方法查找值。
  • func (c *cancelCtx) Done() <-chan struct{}:第一次调用 Done():如果 done 通道还没有创建,程序会在加锁的情况下懒加载创建这个通道。done 通道被存储在 c.done 中,确保后续的 Done() 调用直接返回这个通道。后续调用 Done():后续调用 Done() 时,会直接通过 c.done.Load() 读取已经创建的 done 通道,避免不必要的锁操作,提高了性能。
  • func (c *cancelCtx) Err() error:在锁保护下获取err
func withCancel(parent Context) *cancelCtx {if parent == nil {panic("cannot create context from nil parent")}c := &cancelCtx{}c.propagateCancel(parent, c)return c
}func (c *cancelCtx) propagateCancel(parent Context, child canceler) {c.Context = parentdone := parent.Done()if done == nil {return // parent is never canceled}select {case <-done:// parent is already canceledchild.cancel(false, parent.Err(), Cause(parent))returndefault:}if p, ok := parentCancelCtx(parent); ok {// parent is a *cancelCtx, or derives from one.p.mu.Lock()if p.err != nil {// parent has already been canceledchild.cancel(false, p.err, p.cause)} else {if p.children == nil {p.children = make(map[canceler]struct{})}p.children[child] = struct{}{}}p.mu.Unlock()return}if a, ok := parent.(afterFuncer); ok {// parent implements an AfterFunc method.c.mu.Lock()stop := a.AfterFunc(func() {child.cancel(false, parent.Err(), Cause(parent))})c.Context = stopCtx{Context: parent,stop:    stop,}c.mu.Unlock()return}goroutines.Add(1)go func() {select {case <-parent.Done():child.cancel(false, parent.Err(), Cause(parent))case <-child.Done():}}()
}// parentCancelCtx(parent) 是一个辅助函数,检查父上下文是否是 cancelCtx 类型,
// 或者是否派生自 cancelCtx。
func parentCancelCtx(parent Context) (*cancelCtx, bool) {done := parent.Done()if done == closedchan || done == nil {return nil, false}p, ok := parent.Value(&cancelCtxKey).(*cancelCtx)if !ok {return nil, false}pdone, _ := p.done.Load().(chan struct{})if pdone != done {return nil, false}return p, true
}

propagateCancel实现了 cancelCtx 中的 propagateCancel 方法,它的作用是将取消信号从父上下文(parent)传播到子上下文(child),并根据不同的情况处理取消逻辑。该方法负责建立父子上下文之间的取消关系,当父上下文被取消时,子上下文也会自动取消。这是 Go 语言 context 机制中取消信号传播的核心部分。

func (c *cancelCtx) cancel(removeFromParent bool, err, cause error) {if err == nil {panic("context: internal error: missing cancel error")}if cause == nil {cause = err}c.mu.Lock()if c.err != nil {c.mu.Unlock()return // already canceled}c.err = errc.cause = caused, _ := c.done.Load().(chan struct{})if d == nil {c.done.Store(closedchan)} else {close(d)}for child := range c.children {// NOTE: acquiring the child's lock while holding parent's lock.child.cancel(false, err, cause)}c.children = nilc.mu.Unlock()if removeFromParent {removeChild(c.Context, c)}
}

cancel() 方法用于取消当前上下文,并传播取消信号给它的子上下文。

func removeChild(parent Context, child canceler) {if s, ok := parent.(stopCtx); ok {s.stop()return}p, ok := parentCancelCtx(parent)if !ok {return}p.mu.Lock()if p.children != nil {delete(p.children, child)}p.mu.Unlock()
}

removeChild将子上下文从父上下文中移除。

4.4 timerCtx类
type timerCtx struct {cancelCtxtimer *time.Timer deadline time.Time
}

timerCtxcontext 的一种实现,它用于处理超时(timeout)或截止时间(deadline)。通过嵌入 cancelCtxtimerCtx 实现了取消上下文的能力,并通过计时器控制上下文的超时行为。

func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {return WithDeadline(parent, time.Now().Add(timeout))
}func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {return WithDeadlineCause(parent, d, nil)
}func WithDeadlineCause(parent Context, d time.Time, cause error) (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 sooner than the new one.return WithCancel(parent)}c := &timerCtx{deadline: d,}c.cancelCtx.propagateCancel(parent, c)dur := time.Until(d)if dur <= 0 {c.cancel(true, DeadlineExceeded, cause) // deadline has already passedreturn c, func() { c.cancel(false, Canceled, nil) }}c.mu.Lock()defer c.mu.Unlock()if c.err == nil {c.timer = time.AfterFunc(dur, func() {c.cancel(true, DeadlineExceeded, cause)})}return c, func() { c.cancel(true, Canceled, nil) }
}
  • WithTimeouWithDeadline:用于创建带有超时或截止时间的上下文。超时后自动取消上下文,返回 context.DeadlineExceeded 错误。
  • WithDeadlineCause:核心逻辑处理,创建上下文并设置定时器,定时器到期时自动取消上下文。它还支持设置取消原因(cause)。
  • 取消函数 CancelFunc:无论上下文是否超时,调用 CancelFunc 都可以立即取消上下文。
func (c *cancelCtx) cancel(removeFromParent bool, err, cause error) {if err == nil {panic("context: internal error: missing cancel error")}if cause == nil {cause = err}c.mu.Lock()if c.err != nil {c.mu.Unlock()return // already canceled}c.err = errc.cause = caused, _ := c.done.Load().(chan struct{})if d == nil {c.done.Store(closedchan)} else {close(d)}for child := range c.children {// NOTE: acquiring the child's lock while holding parent's lock.child.cancel(false, err, cause)}c.children = nilc.mu.Unlock()if removeFromParent {removeChild(c.Context, c)}
}

它会关闭与取消相关的通道,取消所有子上下文,必要时将当前上下文从父上下文中移除,并且在第一次取消时设置取消原因。

4.5 valueCtx类
type valueCtx struct {Contextkey, val any
}
  • valueCtx 同样继承了一个 parent context;
  • 一个 valueCtx 中仅有一组 kv 对.
func WithValue(parent Context, key, val any) Context {if parent == nil {panic("cannot create context from nil parent")}if key == nil {panic("nil key")}if !reflectlite.TypeOf(key).Comparable() {panic("key is not comparable")}return &valueCtx{parent, key, val}
}
  • 倘若 parent context 为空,panic;
  • 倘若 key 为空 panic;
  • 倘若 key 的类型不可比较,panic;
  • 包括 parent context 以及 kv对,返回一个新的 valueCtx.
func (c *valueCtx) Value(key any) any {if c.key == key {return c.val}return value(c.Context, key)
}func value(c Context, key any) any {for {switch ctx := c.(type) {case *valueCtx:if key == ctx.key {return ctx.val}c = ctx.Contextcase *cancelCtx:if key == &cancelCtxKey {return c}c = ctx.Contextcase withoutCancelCtx:if key == &cancelCtxKey {// This implements Cause(ctx) == nil// when ctx is created using WithoutCancel.return nil}c = ctx.ccase *timerCtx:if key == &cancelCtxKey {return &ctx.cancelCtx}c = ctx.Contextcase backgroundCtx, todoCtx:return nildefault:return c.Value(key)}}
}
  • 假如当前 valueCtx 的 key 等于用户传入的 key,则直接返回其 value;
  • 假如不等,则从 parent context 中依次向上寻找.

相关文章:

浅析Golang的Context

文章目录 1. 简介2. 常见用法2.1 控制goroutine的生命周期&#xff08;cancel&#xff09;2.2 传递超时&#xff08;Timeout&#xff09;信息2.3 传递截止时间&#xff08;Deadline&#xff09;2.4 传递请求范围内的全局数据 &#xff08;value&#xff09; 3 特点3.1 上下文的…...

生日礼物C++代码

#include<bits/stdc.h> using namespace std; string s; int a,b; int main(){cout<<" 生日之地"<<\n;cout<<" 1.开始游戏"<<" 2.不想开始"<<\n;cin>>a;if(a1||a2){if(a2)cout<<…...

使用python基于DeepLabv3实现对图片进行语义分割

DeepLabv3 介绍 DeepLabv3 是一种先进的语义分割模型&#xff0c;由 Google Research 团队提出。它在 DeepLab 系列模型的基础上进行了改进&#xff0c;旨在提高图像中像素级分类的准确性。以下是 DeepLabv3 的详细介绍&#xff1a; 概述DeepLabv3 是 DeepLab 系列中的第三代…...

【漏洞复现】泛微OA E-Office do_excel.php 任意文件写入漏洞

》》》产品描述《《《 泛微0-0fice是一款标准化的协同 OA办公软件&#xff0c;泛微协同办公产品系列成员之一,实行通用化产品设计&#xff0c;充分贴合企业管理需求&#xff0c;本着简洁易用、高效智能的原则&#xff0c;为企业快速打造移动化、无纸化、数字化的办公平台。 》》…...

算法(食物链)

240. 食物链 题目 动物王国中有三类动物 A,B,C&#x1d434;,&#x1d435;,&#x1d436;&#xff0c;这三类动物的食物链构成了有趣的环形。 A&#x1d434; 吃 B&#x1d435;&#xff0c;B&#x1d435; 吃 C&#x1d436;&#xff0c;C&#x1d436; 吃 A&#x1d434;。…...

ubuntu20.04系统安装zookeeper简单教程

Ubuntu系统中安装和配置Zookeeper的完整指南 Apache Zookeeper是一个开源的分布式协调服务&#xff0c;广泛用于分布式应用程序中管理配置、提供命名服务、分布式同步以及组服务等。在本教程中&#xff0c;我们将详细介绍如何在Ubuntu系统中安装Zookeeper&#xff0c;并进行相关…...

.NET Core 高性能并发编程

一、高性能大并发架构设计 .NET Core 是一个高性能、可扩展的开发框架&#xff0c;可以用于构建各种类型的应用程序&#xff0c;包括高性能大并发应用程序。为了设计和开发高性能大并发 .NET Core 应用程序&#xff0c;需要考虑以下几个方面&#xff1a; 1. 异步编程 异步编程…...

B 私域模式升级:开源技术助力传统经销体系转型

一、引言 1.1 研究背景 随着市场竞争加剧&#xff0c;传统经销代理体系面临挑战。同时&#xff0c;开源技术发展迅速&#xff0c;为 B 私域升级带来新机遇。在当今数字化时代&#xff0c;企业面临着日益激烈的市场竞争。传统的经销代理体系由于管理效率低下、渠道局限、库存压…...

vue之vuex的使用及举例

Vuex是专门为Vue.js设计的集中式状态管理架构&#xff0c;它允许你将所有的组件共享状态存储在一个单独的地方&#xff0c;即“store”&#xff0c;并以相应的规则保证状态以一种可预测的方式发生变化。以下是Vuex的基本使用方法&#xff1a; 一、安装Vuex 对于Vue 2项目&…...

使用 vite 快速初始化 shadcn-vue 项目

Vite 1. 创建项目 使用 vite 创建一个新的 vue 项目。 如果你正在使用 JS 模板&#xff0c;需要存在 jsconfig.json 文件才能正确运行 CLI。 # npm 6.x npm create vitelatest my-vue-app --template vue-ts# npm 7, extra double-dash is needed: npm create vitelatest m…...

微信小程序:一个小程序跳转至另一个小程序

一、微信小程序支持一个小程序跳转至另一个小程序吗&#xff1f; 支持。 1.1、目标小程序需开放被跳转&#xff1a;目标小程序需要在其 app.json 文件中配置 navigateToMiniProgramAppIdList&#xff0c;将源小程序的 AppID 加入其中。 1.2、用户授权&#xff1a;用户需要授…...

Java第二阶段---10方法带参---第二节 方法重载(Overloading)

1.概念 在同一个类中&#xff0c;方法名相同&#xff0c;参数列表不同的多个方法构造成方法重载 2.示例 public class Calculator{public int sum(int a,int b){return ab;}public int sum(int a,int b,int c){return abc;} } 3.误区 下面的方法是否属于方法重载&#xff…...

Java Web 之 Session 详解

在 JavaWeb 开发中&#xff0c;Session 就像网站的专属记忆管家&#xff0c;为每个用户保管着重要的信息和状态&#xff0c;确保用户在网站的旅程顺畅无阻。 场景一&#xff1a; 想象你去一家大型超市购物&#xff0c;推着购物车挑选商品。这个购物车就如同 Session&#xff…...

63.5 注意力提示_by《李沐:动手学深度学习v2》pytorch版

系列文章目录 文章目录 系列文章目录注意力提示生物学中的注意力提示查询、键和值注意力的可视化使用 show_heatmaps 显示注意力权重代码示例 代码解析结果 小结练习 注意力提示 &#x1f3f7;sec_attention-cues 感谢读者对本书的关注&#xff0c;因为读者的注意力是一种稀缺…...

vscode 的terminal 输出打印行数限制设置

修改 VSCODE 的 settings.json文件 "terminal.integrated.scrollback": 100000, {"extensions.ignoreRecommendations": true,"workbench.colorTheme": "Monokai","explorer.confirmDelete": false,"editor.fontSize…...

深入挖掘C++中的特性之一 — 继承

目录 1.继承的概念 2.举个继承的例子 3.继承基类成员访问方式的变化 1.父类成员的访问限定符对在子类中访问父类成员的影响 2.父类成员的访问限定符子类的继承方式对在两个类外访问子类中父类成员的影响 4.继承类模版&#xff08;注意事项&#xff09; 5.父类与子类间的转…...

Linux 下 poll 详解

在Linux系统编程中&#xff0c;poll 是一个强大的多路复用&#xff08;I/O 多路复用&#xff09;函数&#xff0c;用于同时监控多个文件描述符的事件&#xff0c;特别是在处理网络套接字或其他I/O设备时。相比于select&#xff0c;poll 支持监控更多的文件描述符&#xff0c;并…...

virtualbox配置为NAT模式后物理机和虚拟机互通

virtualbox配置为 NAT模式后&#xff0c;虚拟机分配到的 IP地址一般是 10.xx网段的&#xff0c;虚拟机可以通过网络地址转换访问物理机所在的网络&#xff0c;但若不做任何配置&#xff0c;则物理机无法直接访问虚拟机。 virtualbox在提供 NAT配置模式时&#xff0c;也提供了端…...

工程机械车辆挖掘机自卸卡车轮式装载机检测数据集VOC+YOLO格式2644张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2644 标注数量(xml文件个数)&#xff1a;2644 标注数量(txt文件个数)&#xff1a;2644 标注…...

[Notepad++] 文本编辑器的下载及详细安装使用过程(附有下载文件)

程序员常用的文本编辑器Notepad&#xff0c;用于修改配置文件等 下载链接在文末 下载压缩包后解压 &#xff01;&#xff01;安装路径不要有中文 解压文件&#xff0c;得到 双击exe文件 选择简体中文&#xff0c;点击OK 点击下一步 点击“我接受” 更改安装目录&#xff0c;不…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

CTF show Web 红包题第六弹

提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框&#xff0c;很难让人不联想到SQL注入&#xff0c;但提示都说了不是SQL注入&#xff0c;所以就不往这方面想了 ​ 先查看一下网页源码&#xff0c;发现一段JavaScript代码&#xff0c;有一个关键类ctfs…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩

目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...