浅析Golang的Context

news2024/11/22 22:44:43

文章目录

      • 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 main

import (
    "context"
    "fmt"
)

// 创建一个 key 类型,用于在 context 中存储和检索数据
type key string

const userIDKey key = "userID"

// 传递用户 ID 的函数
func processRequest(ctx context.Context) {
    // 从 context 中取出用户 ID
    userID := 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 的 context
    ctx := context.WithValue(context.Background(), userIDKey, "12345")

    // 传递带有用户 ID 的 context
    processRequest(ctx)

    // 调用时没有用户 ID
    processRequest(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() // 取消所有子 goroutine
    time.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() error
	Value(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 {
	Context

	mu       sync.Mutex            // protects following fields
	done     atomic.Value          // of chan struct{}, created lazily, closed by first cancel call
	children map[canceler]struct{} // set to nil by the first cancel call
	err      error                 // set to non-nil by the first cancel call
	cause    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.err
	c.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 = parent

	done := parent.Done()
	if done == nil {
		return // parent is never canceled
	}

	select {
	case <-done:
		// parent is already canceled
		child.cancel(false, parent.Err(), Cause(parent))
		return
	default:
	}

	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 canceled
			child.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 = err
	c.cause = cause
	d, _ := 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 = nil
	c.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 {
	cancelCtx
	timer *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 passed
		return 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 = err
	c.cause = cause
	d, _ := 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 = nil
	c.mu.Unlock()

	if removeFromParent {
		removeChild(c.Context, c)
	}
}

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

4.5 valueCtx类
type valueCtx struct {
	Context
	key, 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.Context
		case *cancelCtx:
			if key == &cancelCtxKey {
				return c
			}
			c = ctx.Context
		case withoutCancelCtx:
			if key == &cancelCtxKey {
				// This implements Cause(ctx) == nil
				// when ctx is created using WithoutCancel.
				return nil
			}
			c = ctx.c
		case *timerCtx:
			if key == &cancelCtxKey {
				return &ctx.cancelCtx
			}
			c = ctx.Context
		case backgroundCtx, todoCtx:
			return nil
		default:
			return c.Value(key)
		}
	}
}
  • 假如当前 valueCtx 的 key 等于用户传入的 key,则直接返回其 value;
  • 假如不等,则从 parent context 中依次向上寻找.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2188657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FWA(固定无线接入),CPE(客户终端设备)简介

文章目录 FWA&#xff08;Fixed Wireless Access&#xff09;&#xff0c;固定无线接入CPE&#xff08;Customer Premise Equipment&#xff09;&#xff0c;用户驻地设备 FWA&#xff08;Fixed Wireless Access&#xff09;&#xff0c;固定无线接入 固定无线接入&#xff08…

Geogebra009—构建正六边形

继续巩固一下基础&#xff0c;本篇我们来做一个正六边形 目录 一、成品展示二、涉及内容三、做图步骤1. 绘制一个以A点为圆心过B点的圆circle1&#xff1b;2. 以B点为圆心过A点绘制另外一个圆circle2&#xff1b;3. 绘制两个圆的交点&#xff0c;得到顶点C和D&#xff1b;4. 以…

Leetcode: 0001-0010题速览

Leetcode: 0001-0010题速览 本文材料来自于LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer&#xff08;第 2 版&#xff09;》、《程序员面试金典&#xff08;第 6 版&#xff09;》题解 遵从开源协议为知识共享 版权归属-相同方式…

奔驰GLS450升级原厂电吸门效果怎么样

奔驰GLS450升级原厂电吸门后&#xff0c;能带来以下效果&#xff1a; • 关门更优雅&#xff1a;只需轻轻推车门到基本关闭的位置&#xff0c;当车门距离车门锁大约6毫米时&#xff0c;传感器便会启动电动马达将车门安静地拉入&#xff0c;然后固定住&#xff0c;告别传统关门…

HTML+CSS基础用法介绍五

目录&#xff1a; 结构伪类选择器盒子模型-边框线盒子模型-内边距盒子模型-解决盒子被撑大盒子模型-外边距与版心居中小知识&#xff1a;清除浏览器中所有标签的默认样式内容溢出控制显示方式盒子模型-圆角 &#x1f40e;正片开始 结构伪类选择器 什么是结构伪类选择器&…

18.安卓逆向-frida基础-调试实战2

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;图灵Python学院 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要盲目相信。 工…

Windows UAC权限详解以及因为权限不对等引发软件工具无法正常使用的实例分析

目录 ​1、什么是UAC&#xff1f; 2、微软为什么要设计UAC&#xff1f; 3、标准用户权限与管理员权限 4、程序到底以哪种权限运行&#xff1f;与哪些因素有关&#xff1f; 4.1、给程序设置以管理员权限运行的属性 4.2、当前登录用户的类型 4.3、如何通过代码判断某个进程…

智能 AI 写作软件:开启创作新纪元

不论你在哪行哪业应该都躲不开写作这件事被。写作已经成为了我们生活和工作中不可或缺的一部分。随着人工智能技术的飞速发展&#xff0c;AI 智能写作工具应运而生。接下来&#xff0c;让我们一起揭开智能ai写作工具的神秘面纱。 1.笔灵AI写作 直通车&#xff1a;https://ibi…

②EtherCAT转ModbusTCP, EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关

EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关https://item.taobao.com/item.htm?ftt&id822721028899 协议转换通信网关 EtherCAT 转 Modbus TCP (接上一章&#xff09; GW系列型号 配置说明 上载 网线连接电脑到模块上的 WEB 网页设置网口&#…

论文笔记:Online Class-Incremental Continual Learning with Adversarial Shapley Value

这篇工作的focus 是 memory-based approach 1. 挑战/问题&#xff1a; 灾难性遗忘&#xff1a;深度神经网络在学习新任务时往往会忘记先前任务的知识。内存和计算效率&#xff1a;在个人设备上执行深度学习任务时&#xff0c;需要最小化内存占用和计算成本。数据流增量学习&am…

系统安全 - 大数据组件的安全及防护

文章目录 导图1. Hadoop的安全风险2. 常见攻击方式3. Hadoop的自带安全功能4. Apache Knox和Apache Ranger等安全框架5. 安全策略建议 导图 1. Hadoop的安全风险 Hadoop最初设计为在可信网络中运行&#xff0c;因此默认安全性较低。常见的安全风险包括&#xff1a; 未经授权的…

探索未来:揭秘pymqtt,AI与物联网的新桥梁

文章目录 探索未来&#xff1a;揭秘pymqtt&#xff0c;AI与物联网的新桥梁背景&#xff1a;为什么选择pymqtt&#xff1f;什么是pymqtt&#xff1f;如何安装pymqtt&#xff1f;简单的库函数使用方法1. 配置MQTT连接2. 创建Mqtt对象3. 发布消息4. 订阅主题5. 运行MQTT客户端 场景…

Java项目实战II基于Java+Spring Boot+MySQL的小徐影城管理系统设计与实现(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者 一、前言 随着文化娱乐产业的快速发展&#xff0c;影城管理面临着日益复杂的挑战&#xff0c;包括票务管理、座…

Redis操作常用API

说明&#xff1a;Redis应用于java项目中&#xff0c;操作Redis数据可以使用API&#xff0c;相较于命令行更方便。使用前&#xff0c;需先添加依赖。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-re…

HIKVISION 海康威视对讲服务配置平台弱口令

漏洞描述 杭州海康威视系统技术有限公司对讲服务配置平台存在弱口令 漏洞复现 FOFA "document.write(TITLE_SYSTEM);" POC admin #账号 12345 #密码 登录成功

利用Spring Boot打造新闻推荐解决方案

1系统概述 1.1 研究背景 如今互联网高速发展&#xff0c;网络遍布全球&#xff0c;通过互联网发布的消息能快而方便的传播到世界每个角落&#xff0c;并且互联网上能传播的信息也很广&#xff0c;比如文字、图片、声音、视频等。从而&#xff0c;这种种好处使得互联网成了信息传…

Kotlin基本知识

Kotlin是一种现代的静态类型编程语言&#xff0c;由JetBrains公司在2010年推出&#xff0c;并被Google在2019年宣布为Android开发的首选语言。 超过 50% 的专业 Android 开发者使用 Kotlin 作为主要语言&#xff0c;而只有 30% 使用 Java 作为主要语言。 70% 以 Kotlin 为主要语…

Redis数据库与GO(二):list,set

一、list&#xff08;列表&#xff09; list&#xff08;列表&#xff09;是简单的字符串列表&#xff0c;按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。List本质是个链表&#xff0c; list是一个双向链表&#xff0c;其元素是有序的&#xff0c;元…

【含文档】基于Springboot+Vue的护肤品推荐系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

ctfshow-web入门(信息收集,持续更新中。。)

写在之前:近期打了个比赛,备受打击,入手了vip账号进修,加油! 文章目录 ctfshow-web1查看源代码ctfshow-web2burp抓包ctfshow-web3burp抓包ctfshow-web4访问robots.txtctfshow-web5dirscarch扫描PHPS文件泄露ctfshow-web6dirscarch扫描ctfshow-web7dirscarch扫描ctfshow-w…