浅析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.WithCancel
或 context.WithTimeout
时,都会基于父 context
创建新的子 context
。
3.3 超时和截止时间
context
允许你为操作设置 超时时间 或 截止时间。通过 context.WithTimeout
和 context.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
}
timerCtx
是 context
的一种实现,它用于处理超时(timeout)或截止时间(deadline)。通过嵌入 cancelCtx
,timerCtx
实现了取消上下文的能力,并通过计时器控制上下文的超时行为。
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) }
}
WithTimeou
和WithDeadline
:用于创建带有超时或截止时间的上下文。超时后自动取消上下文,返回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的生命周期(cancel)2.2 传递超时(Timeout)信息2.3 传递截止时间(Deadline)2.4 传递请求范围内的全局数据 (value) 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 是一种先进的语义分割模型,由 Google Research 团队提出。它在 DeepLab 系列模型的基础上进行了改进,旨在提高图像中像素级分类的准确性。以下是 DeepLabv3 的详细介绍: 概述DeepLabv3 是 DeepLab 系列中的第三代…...

【漏洞复现】泛微OA E-Office do_excel.php 任意文件写入漏洞
》》》产品描述《《《 泛微0-0fice是一款标准化的协同 OA办公软件,泛微协同办公产品系列成员之一,实行通用化产品设计,充分贴合企业管理需求,本着简洁易用、高效智能的原则,为企业快速打造移动化、无纸化、数字化的办公平台。 》》…...

算法(食物链)
240. 食物链 题目 动物王国中有三类动物 A,B,C𝐴,𝐵,𝐶,这三类动物的食物链构成了有趣的环形。 A𝐴 吃 B𝐵,B𝐵 吃 C𝐶,C𝐶 吃 A𝐴。…...

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

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

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

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

使用 vite 快速初始化 shadcn-vue 项目
Vite 1. 创建项目 使用 vite 创建一个新的 vue 项目。 如果你正在使用 JS 模板,需要存在 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…...

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

Java第二阶段---10方法带参---第二节 方法重载(Overloading)
1.概念 在同一个类中,方法名相同,参数列表不同的多个方法构造成方法重载 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.误区 下面的方法是否属于方法重载ÿ…...

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

63.5 注意力提示_by《李沐:动手学深度学习v2》pytorch版
系列文章目录 文章目录 系列文章目录注意力提示生物学中的注意力提示查询、键和值注意力的可视化使用 show_heatmaps 显示注意力权重代码示例 代码解析结果 小结练习 注意力提示 🏷sec_attention-cues 感谢读者对本书的关注,因为读者的注意力是一种稀缺…...

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.继承类模版(注意事项) 5.父类与子类间的转…...

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

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

工程机械车辆挖掘机自卸卡车轮式装载机检测数据集VOC+YOLO格式2644张3类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2644 标注数量(xml文件个数):2644 标注数量(txt文件个数):2644 标注…...

[Notepad++] 文本编辑器的下载及详细安装使用过程(附有下载文件)
程序员常用的文本编辑器Notepad,用于修改配置文件等 下载链接在文末 下载压缩包后解压 !!安装路径不要有中文 解压文件,得到 双击exe文件 选择简体中文,点击OK 点击下一步 点击“我接受” 更改安装目录,不…...

深入浅出Java多线程(六):Java内存模型
引言 大家好,我是你们的老伙计秀才!今天带来的是[深入浅出Java多线程]系列的第六篇内容:Java内存模型。大家觉得有用请点赞,喜欢请关注!秀才在此谢过大家了!!! 在并发编程中…...

注册了个小趴菜999#it#com
注册了个 999#it#com 拿着玩玩吧 现在二级域名竟然也让注册了 不过cn.com的二级似乎早就可以了...

UE4 材质学习笔记02(数据类型/扭曲着色器)
一.什么是数据类型 首先为啥理解数据类型是很重要的。一些节点的接口插槽只接受特定类型的数据,如果连接了不匹配的数据就会出现错误,有些接口可以接受任何数据类型,但是实际上只会使用到其中的一些。并且有时可以将多个数据流合并成一个来编…...

Linux驱动开发(速记版)--设备树插件
第六十八章 设备树插件介绍 Linux 4.4之后引入了动态设备树,其中的设备树插件(Device Tree Overlay)是一种扩展机制,允许在运行时动态添加、修改或删除设备节点和属性。 设备树插件机制通过DTS(设备树源文件࿰…...

代码报错后如何定位问题
文章目录 一、查看终端报错Exception二、百度三、问 一、查看终端报错Exception 代码报错时,终端一般都会有xxxException异常提示,或者exception、error…等字样提示,就顺着这些关键字提醒找到异常即可。 二、百度 不知道这个英文的异常是…...

Python数据可视化--Matplotlib--入门
我生性自由散漫,不喜欢拘束。我谁也不爱,谁也不恨。我没有欺骗这个,追求那个;没有把这个取笑,那个玩弄。我有自己的消遣。 -- 塞万提斯 《堂吉诃德》 Matplotlib介绍 1. Matplotlib 是 Python 中常用的 2D 绘图库&a…...

美国食品等级FDA认证测试介绍
美国FDA认证概览 美国食品和药物管理局(FDA)是负责监管食品、药品、医疗设备和化妆品等的联邦机构,以确保这些产品对公众健康和安全的影响。FDA认证在美国属于强制性认证,对产品的安全性和质量有着严格的要求。通过FDA认证&#…...

Vue2如何在网页实现文字的逐个显现
目录 Blue留言: 效果图: 实现思路: 代码: 1、空字符串与需渲染的字符串的定义 2、vue的插值表达式 3、函数 4、mounted()函数调用 结语: Blue留言: 在国庆前夕,突发奇想,我想…...

mybatisplus的查询,分页查询,自定义多表查询,修改的几种写法
使用mybatisplus的Db类简化写法 使用静态调用的方式,执行CRUD方法,避免Spring环境下Service循环注入、简洁代码,提升效率需要项目中已注入对应实体的BaseMapper完整使用方式见官方测试用例:官方测试用例地址对于参数为Wrapper的&…...

括号匹配判断
本题实现求表达式中括号是否匹配。只需判断表达式中括号(本题中只会出现三种括号,分别是小括号,中括号和大括号)是否匹配,表达式中可以有其他值也可没有。 函数接口定义: int match (char *exp); 其中 …...