Golang | 腾讯一面

news2024/9/28 17:55:05

go的调度

Golang的调度器采用M:N调度模型,其中M代表用户级别的线程(也就是goroutine),而N代表的事内核级别的线程。Go调度器的主要任务就是N个OS线程上调度M个goroutine。这种模型允许在少量的OS线程上运行大量的goroutine

Go调度器使用了三种队列来管理goroutine

  1. 全局队列(Global Queue):此队列中包含了所有刚创建的goroutine
  2. 本地队列(Local Queue):每个P(Processor,处理器)都有一个本地队列,P会有限从本地队列中取出goroutine来执行。
  3. 网络轮循器(Netpoller):此队列中包含了所有在等待网络时间(如IO操作)的goroutine。当网络事件就绪时,对应的goroutine会被放入到全局队列中,等待被P取出。

Go的调度器采用了工作窃取(Work Stealing)和手动抢占(Preemption)的策略

  • 工作窃取:当一个P的本地队列中没有goroutine时,它会尝试从全局队列或其他P的本地队列中窃取goroutine来执行。
  • 手动抢占:为了防止一个goroutine长时间占用P而导致其他goroutine饿死,Go的调度器会定期地进行抢占操作。在Go 1.14之前,Go的调度器只在函数调用时才会进行抢占,从Go 1.14开始引入了异步抢占,即允许在任何安全点进行抢占。

go struct能不能比较

Golangstruct是否能比较取决于struct内变量的类型:

所有字段可比较:只有当结构体的所有字段都可以进行比较时,结构体本身才可以进行比较。如果结构体包含不可比较的字段,如切片(slice)、映射(map)或函数(func),则该结构体不能进行比较。

逐字段比较:结构体的比较是逐字段进行的,即比较结构体的每个字段的值。如果所有字段的值都相等,则两个结构体相等;否则,它们不相等。

go defer

基本用法

在Go语言中,defer关键字用于在函数返回前执行一段代码或调用一个清理函数。这对于处理文件关闭、解锁或者返回一些资源到资源池等操作非常有用。

其基本用法如下所示:

package main

import "fmt"

func main() {
	example()
}

func example() {
	defer fmt.Println("world")
	fmt.Println("hello")
}

defer fmt.Println("world")语句会在函数example返回之前执行,所以输出的结果是:

在这里插入图片描述

执行顺序

当我们在一个函数内部调用defer关键字,Go实际上会把它后面的函数(通常是一个匿名函数或者清理函数)压入一个栈中。当外部函数准备返回的时候,Go会按照先进先出的(LIFO)的顺序调用并执行这个栈中的所有函数。

比如,如下示例:

package main

import "fmt"

func main() {
	example()
}

func example() {
	defer fmt.Println("first")
	defer fmt.Println("second")
	defer fmt.Println("third")
	fmt.Println("function body")
}

其输出结果为:在这里插入图片描述

参数计算时机

需要注意的是,defer语句的参数会在defer语句处就计算好,而不是在外部函数返回时才计算。比如如下例子

package main

import "fmt"

func main() {
	example()
}

func example() {
	i := 0
	defer fmt.Println(i) 
	i++
	fmt.Println(i)
}
/*
1
0
*/

实际应用举例

关闭文件
package main

import (
	"fmt"
	"io/ioutil"
	"os"
)

func readFile(fileName string) (string, error) {
	file, err := os.Open(fileName)
	if err != nil {
		return "", err
	}
	defer file.Close() // 确保文件在函数返回前被关闭

	content, err := ioutil.ReadAll(file)
	if err != nil {
		return "", err
	}
	return string(content), nil
}

func main() {
	content, err := readFile("example.txt")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println("File content:", content)
}
解锁互斥锁
package main

import (
	"fmt"
	"sync"
)

var mtx sync.Mutex
var cnt int

const N int = 10

func increment() {
	mtx.Lock()
	defer mtx.Unlock()
	cnt++
}

func main() {
	var wg sync.WaitGroup

	for i := 0; i < N; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			increment()
		}()
	}

	wg.Wait()
	fmt.Println("Final count: ", cnt)
}

释放网络连接
package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func fetchURL(url string) (string, error) {
	resp, err := http.Get(url)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close() // 确保连接在函数返回前被关闭

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

func main() {
	content, err := fetchURL("http://baidu.com")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println("URL content:", content)
}

select可以用于什么

select关键字用于处理同时来自多个通道的数据。它的基本工作原理是“随机选择”满足条件的分支去执行。如果没有分支满足条件(即所有通道都无法读/写),select会阻塞,直到有分支满足条件。如果select包含default分支,当其他分支都不满足条件时,default分支会被执行。

Goselect底层使用了一种名为scase的结构体,表示一个select分支,包含了通道和对应的操作类型(发送或者接收)。同时,它还会使用一个名为hchan 的结构体来表示通道的内部结构。

以下是select的一些重要的特性:

  • 公平性:在Go语言中,select语言会随机选择一个可以运行的case执行,保证了每一个case都有公平的机会被执行,避免了饥饿问题。
  • 非阻塞:如果select中所有的case都无法运行,而且存在default分支,那么select就不会被阻塞,而是执行default分支。
  • 可用于时间操作select经常与time.After, time.Tick等函数一起使用,用于实现超时操作或者定时操作。
  • 可用于退出操作select经常和context一起使用,当收到context的取消信号时,可以安全地退出协程。
package main

import (
	"fmt"
	"time"
)

func selectExample(c1, c2 chan int, quit chan bool) {
	for {
		select {
		case v := <-c1:
			fmt.Println("Received from c1:", v)
		case v := <-c2:
			fmt.Println("Received from c2:", v)
		case <-quit:
			fmt.Println("Quit signal received. Exiting.")
			return
		default:
			fmt.Println("No data received.")
			time.Sleep(1 * time.Second) // 添加延迟以避免过度占用CPU
		}
	}
}

func main() {
	// 创建通道
	c1 := make(chan int)
	c2 := make(chan int)
	quit := make(chan bool)

	// 启动selectExample函数作为goroutine
	go selectExample(c1, c2, quit)

	// 启动发送数据到c1的goroutine
	go func() {
		for i := 0; i < 5; i++ {
			c1 <- i
			time.Sleep(1 * time.Second)
		}
	}()

	// 启动发送数据到c2的goroutine
	go func() {
		for i := 0; i < 5; i++ {
			c2 <- i + 10
			time.Sleep(2 * time.Second)
		}
	}()

	// 从主goroutine发送退出信号
	time.Sleep(10 * time.Second) // 等待足够时间以查看输出
	quit <- true
	fmt.Println("Sent quit signal and waiting to exit.")
}

context包的用途

Golang中,context为我们提供了在跨API边界和进程之间传递请求作用域的deadline,取消信号,和其他请求响应的值的能力。

context包定义了Context类型,它在API边界和进程之间提供了一种传递传递请求作用域的deadline,取消信号,和其他请求响应的值的能力。一个Context的生命周期通常与请求处理的生命周期相同,并且可以包含在多个API调用和goroutine之间共享数据和取消信号。

context的主要方法有:
  • Deadline:返回当前Context合适会被取消。如果Context不会被取消,则返回ok为false
  • Done:返回一个通道,当Context被取消或超时的时候,该通道会被关闭。
  • Err:返回Context为何被取消。
  • Value:返回与Context相关的值,这些值必须是线程安全的。

Go语言的context包提供了两个函数用于创建Context对象:context.Background()context.TODO(),前者通常用在主函数、初始化以及测试代码中,表示一个空的Context,后者通常用在不确定应该使用什么Context,或者函数以后会更新以便接受一个Context参数。

此外,context包还提供了WithCancelWithDeadlineWithTimeoutWithValue函数,从现有的Context派生出新的Context

  • context.Background(): 返回一个空的Context,这个Context通常被用在main函数、初始化以及测试时。
  • context.TODO(): 当不确定应该使用什么Context,或者还未决定如何传递Context时,可以使用这个。
  • context.WithCancel(parent Context) (ctx Context, cancel CancelFunc): 根据已有的Context创建一个新的可取消的Context。
  • context.WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc): 根据已有的Context和设置的截止时间创建一个新的Context。
  • context.WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc): 基于已有的Context和指定的超时时间创建一个新的Context。
使用场景:
  1. 超时控制:我们可以通过context.WithTimeout创建一个超时的Context,当超时时间到达,该Context就会自动取消。比如,在数据库操作或外部服务调用时,可以通过设置超时的context来防止系统因为某个部分的响应缓慢而整体性能下降。
  2. 请求传递:在微服务或者并发编程的环境中,我们可以通过context.WithValue将请求相关的数据绑定到Context中,在函数调用链路上下游之间传递。
  3. 请求取消:我们可以通过Context.WithCancelcontext.WithTimeout创建一个可被取消的Context,并在需要取消的时候调用Contextcancel函数。比如在Web服务器中,如果客户端中断了请求,服务器可以通过context来取消所有相关的goroutine,从而避免资源浪费。
  4. 优雅地处理goroutine的生命周期: 通过contextDone通道,可以监听到取消信号,从而在goroutine中适时地释放资源,停止执行,保证程序的健売性和响应性。
package main

import (
	"context"
	"fmt"
	"time"
)

func calculate(ctx context.Context, ch chan []int) {
	for {
		select {
		case data := <-ch:
			// 模拟一些处理过程
			process(data)
		case <-ctx.Done():
			// 如果context收到取消信号(超时或显式取消),则停止操作
			return
		}
	}
}

func process(data []int) {
	// 实际处理数据的函数
	fmt.Println(data)
}

func ContextCase() {
	ctx := context.Background()                         // 创建一个背景context
	ctx = context.WithValue(ctx, "desc", "ContextCase") // 向context中添加键值对,这里添加描述信息"ContextCase"

	// 创建一个带有超时的context,超时时间为2秒
	ctx, cancel := context.WithTimeout(ctx, time.Second*2)
	defer cancel() // 确保在函数结束时取消context,以释放相关资源

	data := [][]int{ // 初始化数据
		{1, 2},
		{3, 2},
	}
	ch := make(chan []int) // 创建一个传递数据的channel
	go calculate(ctx, ch)  // 启动一个goroutine来处理从channel接收的数据
	for i := 0; i < len(data); i++ {
		ch <- data[i] // 向channel发送数据
	}

	time.Sleep(time.Second * 10) // 主goroutine睡眠10秒
}

func main() {
	ContextCase()
}

client如何实现长连接

  • 使用 net 包进行低级 TCP 连接,适用于自定义协议或非 HTTP 通信。
  • 使用 http 包配置 http.Client 保持 HTTP 连接。
  • 使用 WebSocket 实现实时双向通信,适用于需要实时数据传输的应用。

主协程如何等其余协程完再操作

使用sync.WaitGroup()

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup
    // 启动多个协程
    numGoroutines := 3
    for i := 1; i <= numGoroutines; i++ {
        wg.Add(1) // 每启动一个协程前调用 Add(1)

        go func(id int) {
            defer wg.Done() // 协程完成后调用 Done()
            fmt.Printf("Goroutine %d is working...\n", id)
            time.Sleep(time.Second * time.Duration(id))
            fmt.Printf("Goroutine %d is done.\n", id)
        }(i)
    }

    // 等待所有协程完成
    wg.Wait()

    fmt.Println("All goroutines have completed. Main function can proceed.")
}

slice,len,cap,共享,扩容

len求当前元素的数量,即长度。cap求切片的容量。

Golang切片的扩容机制如下:

  1. 初始容量
    • 新创建的切片默认容量为0或根据创建时提供的元素数量确定。
  2. 扩容规则
    • 当需要扩容时,Go语言的切片扩容机制通常是将其容量翻倍(cap *= 2),直到达到一定的阈值后(例如1024),扩容策略改为每次增长大约1/4(cap += cap / 4),以降低大型切片的扩容开销。
    • 自Go 1.16版本开始,扩容策略稍有改变,但仍基于翻倍原则,但在容量大于1024时,并非简单地增加1/4,而是使用更复杂的算法,旨在更好地平衡内存使用和性能。
  3. 特殊情况
    • 当切片的当前容量小于1000时,Go可能并不会严格遵循上述翻倍策略,而是采用更保守的扩容策略,以适应小容量切片的需求。
    • 如果所需的新增容量远大于当前容量,Go可能会直接将容量设置为所需容量,而不是简单地翻倍。
  4. 性能考量
    • 扩容操作伴随着内存分配和数据拷贝,因此在编写代码时应尽量避免过于频繁的扩容操作,可以预先估计数据量并使用make函数指定合适的初始容量。

map如何顺序读取

map本身是无顺序的,所以要想顺序读取,就必须将map中的内容存到一个切片中,然后对切片进行排序。

实现set

通过map来实现,map 的键可以用来存储集合中的元素,而值可以被设为 struct{}bool。使用 struct{} 的好处是它不占用额外的内存空间。

package main

import (
	"fmt"
)

// Set 结构体表示一个集合
type Set struct {
	elements map[string]struct{}
}

// NewSet 创建一个新的 Set
func NewSet() *Set {
	return &Set{
		elements: make(map[string]struct{}),
	}
}

// Add 向集合中添加元素
func (s *Set) Add(element string) {
	s.elements[element] = struct{}{}
}

// Remove 从集合中删除元素
func (s *Set) Remove(element string) {
	delete(s.elements, element)
}

// Contains 检查集合中是否包含某个元素
func (s *Set) Contains(element string) bool {
	_, exists := s.elements[element]
	return exists
}

// Size 返回集合中元素的数量
func (s *Set) Size() int {
	return len(s.elements)
}

// Clear 清空集合
func (s *Set) Clear() {
	s.elements = make(map[string]struct{})
}

// Elements 返回集合中的所有元素
func (s *Set) Elements() []string {
	keys := make([]string, 0, len(s.elements))
	for k := range s.elements {
		keys = append(keys, k)
	}
	return keys
}

func main() {
	mySet := NewSet()

	mySet.Add("apple")
	mySet.Add("banana")
	mySet.Add("orange")

	fmt.Println("Set contains 'apple':", mySet.Contains("apple")) 
	fmt.Println("Set size:", mySet.Size())                        

	mySet.Remove("banana")
	fmt.Println("Set contains 'banana':", mySet.Contains("banana")) 
	fmt.Println("Set elements:", mySet.Elements())                   
}

实现消息队列(多生产者,多消费者)

定义生产者和消费者函数

  • producer 函数生成消息并将其发送到通道。
  • consumer 函数从通道接收消息并处理它们。

创建一个带缓冲的通道

  • queue 是一个带缓冲的通道,用来在生产者和消费者之间传递消息。

启动多个生产者和消费者

  • 使用 sync.WaitGroup 来跟踪生产者和消费者的完成情况。
  • 每个生产者和消费者在各自的 goroutine 中运行。

等待所有生产者完成并关闭通道

  • 使用 wg.Wait() 等待所有生产者完成。
  • 关闭通道以通知消费者没有更多消息。

等待所有消费者完成

  • 使用另一个 sync.WaitGroup 来跟踪消费者的完成情况。
  • 确保所有消费者在通道关闭后都能处理完剩余的消息。
package main

import (
    "fmt"
    "sync"
    "time"
)

// 生产者函数
func producer(id int, queue chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        msg := id*10 + i
        fmt.Printf("Producer %d: produced %d\n", id, msg)
        queue <- msg
        time.Sleep(time.Millisecond * 100) // 模拟生产时间
    }
}

// 消费者函数
func consumer(id int, queue <-chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for msg := range queue {
        fmt.Printf("Consumer %d: consumed %d\n", id, msg)
        time.Sleep(time.Millisecond * 150) // 模拟消费时间
    }
}

func main() {
    var wg sync.WaitGroup

    queue := make(chan int, 10) // 创建一个带缓冲的通道

    // 启动多个生产者
    numProducers := 3
    for i := 1; i <= numProducers; i++ {
        wg.Add(1)
        go producer(i, queue, &wg)
    }

    // 启动多个消费者
    numConsumers := 2
    for i := 1; i <= numConsumers; i++ {
        wg.Add(1)
        go consumer(i, queue, &wg)
    }

    // 等待所有生产者完成
    wg.Wait()
    close(queue) // 关闭通道以通知消费者没有更多消息

    // 再次等待所有消费者完成
    var consumerWg sync.WaitGroup
    for i := 1; i <= numConsumers; i++ {
        consumerWg.Add(1)
        go func() {
            defer consumerWg.Done()
            for msg := range queue {
                fmt.Printf("Final Consumer %d: consumed %d\n", i, msg)
                time.Sleep(time.Millisecond * 150)
            }
        }()
    }
    consumerWg.Wait()
}

大文件排序

分块排序

  • 使用将大文件分块读取到内存,每次读取 chunk_size 行。
  • 对每个小块进行排序,并将已排序的小块写入临时文件。
  • 将每个小块文件的路径存储在 chunks 列表中。

归并排序

  • 打开所有小块文件,并初始化一个最小堆,将每个文件的第一行加入堆中。
  • 逐步从堆中取出最小元素,并将其写入输出文件。
  • 从相应的小块文件中读取下一行数据,如果该文件未读完,将下一行数据加入堆中;否则,关闭该文件。
  • 重复以上过程直到堆为空,表示所有数据已排序并写入输出文件。

清理临时文件

  • 合并完成后,删除所有临时小块文件。

基本排序,哪些是稳定的

稳定的排序算法:冒泡排序、插入排序、归并排序、基数排序、计数排序。

不稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。

Http get跟head

HTTP GET

功能
  • 请求资源GET 请求用于从服务器请求指定的资源。服务器返回资源的内容和相关的头部信息。
  • 常见用途:获取网页内容、下载文件、获取 API 数据等。
特点
  • 包含响应体GET 请求的响应通常包含资源的完整内容,即响应体。
  • 安全性和幂等性GET 请求是安全的(不会改变服务器的状态),也是幂等的(多次相同请求结果相同)。
示例
GET /index.html HTTP/1.1
Host: www.example.com

HTTP HEAD

功能
  • 请求头部信息HEAD 请求与 GET 请求类似,但服务器只返回头部信息,不返回响应体。
  • 常见用途:检查资源是否存在、获取资源的元数据(如内容类型、长度、最后修改时间等)。
特点
  • 无响应体HEAD 请求的响应不包含资源的内容,只有头部信息。
  • 安全性和幂等性HEAD 请求是安全的,也是幂等的,通常用于在不下载整个资源的情况下获取资源的信息。
示例
HEAD /index.html HTTP/1.1
Host: www.example.com

Http 401,403

状态码含义主要原因重试机会
401未授权客户端未通过身份验证或未提供有效的凭据可以,通过提供正确的身份验证信息
403禁止访问客户端已通过身份验证,但没有权限访问资源不可以,权限问题无法通过重试解决

Http keep-alive

在 HTTP/1.0 中,每个请求/响应对都是通过单独的 TCP 连接来处理的,这意味着每次请求都需要开销较大的连接建立和关闭过程。HTTP/1.1 引入了持久连接(persistent connections),即 Keep-Alive,允许在同一个连接上处理多个请求和响应。

GET /index.html HTTP/1.1
Host: www.example.com
Connection: keep-alive
Keep-Alive: timeout=10, max=100

timeout=10 表示如果在10秒内没有新的请求,连接将关闭;max=100 表示最多可以在该连接上发送100个请求。

Http能不能一次连接多次请求,不等后端返回

  1. 并行请求: 虽然单个 TCP 连接只能处理一个请求的响应周期,但客户端可以通过创建多个 TCP 连接来实现并行请求。通常,浏览器和现代 HTTP 客户端会使用多个并发的 TCP 连接来同时发起多个请求,以减少请求之间的等待时间。
  2. HTTP/2 多路复用: HTTP/2 协议支持在同一个 TCP 连接上进行多个并发的请求和响应。这种技术称为多路复用(Multiplexing),它允许多个 HTTP 请求和响应同时在同一个连接上进行传输,提高了性能和效率。
  3. 长连接(Keep-Alive): HTTP/1.1 引入了持久连接(Keep-Alive),允许在同一个 TCP 连接上发送多个 HTTP 请求和响应。在此模式下,客户端在发送完一个请求后不关闭连接,可以继续发送其他请求,服务器也可以在响应后保持连接打开以发送后续响应。这种方式虽然不能真正并行发送多个请求,但可以减少连接的建立和关闭开销,提升效率。

time-wait的作用

确保连接的正确关闭: TIME_WAIT状态允许所有可能的延迟数据包被接收和处理,避免新的连接收到旧连接的数据包。

防止重复的数据包: 由于TCP连接关闭时,可能还有一些数据包在网络中传输。进入TIME_WAIT状态可以确保这些数据包有足够的时间被处理,避免影响后续连接。

提供时间处理丢失的FIN包: 在关闭连接的过程中,双方需要确认FIN包。如果ACK包丢失了,发送FIN的一方需要在TIME_WAIT期间重新发送FIN包,确保连接能正常关闭。

避免端口重用冲突: TIME_WAIT状态确保在特定时间内,不能重用同一端口,以防止与旧连接的冲突。

数据库如何建索引

1. 基本索引类型

  1. B-树索引

    • 最常见的索引类型,适用于大多数情况。
    • 在MySQL中使用CREATE INDEX语句创建B-树索引。
    CREATE INDEX index_name ON table_name(column_name);
    
  2. 唯一索引

    • 确保索引列中的所有值都是唯一的。
    CREATE UNIQUE INDEX index_name ON table_name(column_name);
    
  3. 全文索引

    • 用于全文搜索,适用于大文本字段的快速搜索。
    • MySQL中可以对TEXT类型的字段使用全文索引。
    CREATE FULLTEXT INDEX index_name ON table_name(column_name);
    
  4. 哈希索引

    • 基于哈希表的索引,适用于等值查询。
    • 一些数据库如MySQL的Memory引擎支持哈希索引。
    CREATE INDEX index_name USING HASH ON table_name(column_name);
    

2. 创建复合索引

复合索引是基于多个列创建的索引,适用于涉及多个列的查询。

CREATE INDEX index_name ON table_name(column1, column2);

孤儿进程,僵尸进程

孤儿进程 (Orphan Process)

孤儿进程是指父进程已经终止,但子进程仍在运行的进程。操作系统会自动将孤儿进程的父进程重新分配给系统的init进程(在Unix和Linux系统中,PID为1的进程),从而确保这些孤儿进程不会没有父进程。

僵尸进程 (Zombie Process)

僵尸进程是指一个已经终止的子进程,但它的退出状态信息仍然保存在系统中,尚未被父进程读取。这个进程占用了一个进程ID(PID),但没有实际的进程资源。僵尸进程通常由父进程在调用wait()waitpid()函数之前子进程终止时产生。

git文件版本,使用顺序,merge跟rebase

Merge(合并)

git merge用于将一个分支的更改合并到当前分支。合并操作会创建一个新的提交,记录分支合并的历史。

git checkout main
git merge new_feature
Rebase(变基)

git rebase用于将一个分支上的提交应用到另一个分支的基础之上。它会重写提交历史,使之看起来像是在目标分支的基础上直接进行的更改。

git checkout new_feature
git rebase main

最后给大家推荐一个LinuxC/C++高级架构系统教程的学习资源与课程,可以帮助你有方向、更细致地学习C/C++后端开发,具体内容请见 https://xxetb.xetslk.com/s/1o04uB

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

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

相关文章

基于STM32瑞士军刀--【FreeRTOS开发】学习笔记(二)|| 堆 / 栈

堆和栈 1. 堆 堆就是空闲的一块内存&#xff0c;可以通过malloc申请一小块内存&#xff0c;用完之后使用再free释放回去。管理堆需要用到链表操作。 比如需要分配100字节&#xff0c;实际所占108字节&#xff0c;因为为了方便后期的free&#xff0c;这一小块需要有个头部记录…

2024年7月25日(Git gitlab以及分支管理 )

分布式版本控制系统 一、Git概述 Git 是一种分布式版本控制系统,用于跟踪和管理代码的变更。它是由Linus Torvalds创建的,最 初被设计用于Linux内核的开发。Git允许开发人员跟踪和管理代码的版本,并且可以在不同的开 发人员之间进行协作。 Github 用的就是Git系统来管理它们的…

JVM面试题之内存区域、类加载篇

文章目录 引言JVM是什么&#xff1f;1. JVM内存划分2. 对象如何在JVM中创建2.1 内存分配2.2 创建对象步骤 3. JVM类加载流程3.1 双亲委派 总结 引言 Java开发人员在面试中基本都会被问到关于JVM的问题。想要成为高级的开发人员&#xff0c;了解和学习Java运行的原理和JVM是必不…

webpack插件给所有的:src文件目录增加前缀

1.webpack4的版本写法 class AddPrefixPlugin {apply(compiler) {compiler.hooks.compilation.tap(AddPrefixPlugin, (compilation) > {HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync(AddPrefixPlugin,(data, cb) > {// 使用正则表达式替换所有包含 /st…

阿里云服务器安装Anaconda后无法检测到

前言 问题如标题所言&#xff0c;就是conda -V验证错误&#xff0c;不过后来发现其实就是虽然安装时&#xff0c;同意了写入环境变量&#xff0c;但是其实还没有写入&#xff0c;需要手动写入。下面也会重复一遍安装流程。 安装 到[Anaconda下载处](Download Now | Anaconda)查…

基于微信小程序+SpringBoot+Vue的流浪动物救助(带1w+文档)

基于微信小程序SpringBootVue的流浪动物救助(带1w文档) 基于微信小程序SpringBootVue的流浪动物救助(带1w文档) 本系统实现的目标是使爱心人士都可以加入到流浪动物的救助工作中来。考虑到救助流浪动物的爱心人士文化水平不齐&#xff0c;所以本系统在设计时采用操作简单、界面…

通过IEC104转MQTT网关对接阿里云、华为云、亚马逊AWS、ThingsBoard、Ignition、Zabbix

随着工业互联网的快速发展&#xff0c;传统电力系统中的IEC 104协议设备正逐步向更加开放、灵活的物联网架构转型。MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;作为一种轻量级的消息传输协议&#xff0c;因其低带宽消耗、高可靠性和广泛的支持性&#xf…

【JavaSE】基础知识复习 (二)

1.面向对象 对象内存分析 举例&#xff1a; class Person { //类&#xff1a;人String name;int age;boolean isMale; } public class PersonTest { //测试类public static void main(String[] args) {Person p1 new Person();p1.name "赵同学";p1.age 20;p1.is…

CentOS搭建Apache服务器

安装对应的软件包 [roothds ~]# yum install httpd mod_ssl -y 查看防火墙的状态和selinux [roothds ~]# systemctl status firewalld [roothds ~]# cat /etc/selinux/config 若未关闭&#xff0c;则关闭防火墙和selinux [roothds ~]# systemctl stop firewalld [roothds ~]# …

使用html2canvas制作一个截图工具

0 效果 1 下载html2canvas npm install html2canvas --save 2 创建ClipScreen.js import html2canvas from html2canvas; // 样式 const cssText {box: overflow:hidden;position:fixed;left:0;top:0;right:0;bottom:0;background-color:rgba(255,255,255,0.9);z-index: 10…

【嵌入式硬件】快衰减和慢衰减

1.引语 在使用直流有刷电机驱动芯片A4950时,这款芯片采用的是PWM控制方式,我发现他的正转、反转有两种控制方式,分别是快衰减和慢衰减。 2.理解 慢衰减:相当于加在电机(感性原件)两端电压消失,将电机两端正负短接。 快衰减:相当于加在电机(感性原件)两端电压消失,将电机…

一篇文章讲清楚html css js三件套之html

目录 HTML HTML发展史 HTML概念和语法 常见的HTML标签: HTML 调试 错误信息分析 HTML文档结构 HTML5的新特性 结论 HTML HTML是网页的基础&#xff0c;它是一种标记语言&#xff0c;用于定义网页的结构和内容。HTML标签告诉浏览器如何显示网页元素&#xff0c;例如段落…

快速安装torch-gpu和Tensorflow-gpu(自用,Ubuntu)

要更详细的教程可以参考Tensorflow PyTorch 安装&#xff08;CPU GPU 版本&#xff09;&#xff0c;这里是有基础之后的快速安装。 一、Pytorch 安装 conda create -n torch_env python3.10.13 conda activate torch_env conda install cudatoolkit11.8 -c nvidia pip ins…

WINUI——Microsoft.UI.Xaml.Markup.XamlParseException:“无法找到与此错误代码关联的文本。

开发环境 VS2022 .net core6 问题现象 在Canvas内的子控件要绑定Canvas的兄弟控件的一个属性&#xff0c;在运行时出现了下述报错。 可能原因 在 WinUI&#xff08;特别是用于 UWP 或 Windows App SDK 的版本&#xff09;中&#xff0c;如果你尝试在 XAML 中将 Canvas 内的…

CSS 的工作原理

我们已经学习了CSS的基础知识,它的用途以及如何编写简单的样式表。在本课中,我们将了解浏览器如何获取 CSS 和 HTML 并将其转换为网页。 先决条件:已安装基本软件,了解处理文件的基本知识以及 HTML 基础知识(学习 HTML 简介。目的:要了解浏览器如何解析 CSS 和 HTML 的基…

pytorch前馈神经网络--手写数字识别

前言 具体内容就是&#xff1a; 输入一个图像&#xff0c;经过神经网络后&#xff0c;识别为一个数字。从而实现图像的分类。 资源&#xff1a; https://download.csdn.net/download/fengzhongye51460/89578965 思路&#xff1a; 确定输入的图像&#xff1a;会单通道灰度的…

即时战略游戏:帝国时代2 for Mac 3.3.1769 中文移植版

帝国时代II蛮王崛起是一款非常经典的即时战略游戏&#xff0c;新的地图&#xff0c;四个新战役&#xff0c;新的AI进行整合。帝国时代2玩家将要探索来自“国王时代”和“征服者”扩张的所有原始单人游戏&#xff0c;选择跨越一千年历史的18个文明&#xff0c;并在线上挑战其他玩…

17 敏捷开发—Scrum(2)

从上一篇 「16 敏捷开发实践&#xff08;1&#xff09;」中了解了Scrum是一个用于开发和维护复杂产品的框架&#xff0c;是一个增量的、迭代的开发过程。一般由多个Sprint&#xff08;迭代冲刺&#xff09;组成&#xff0c;每个Sprint长度一般为2-4周。下面全面介绍Scrumde 角色…

2024第29届郑州全国商品交易会

第29届郑州全国商品交易会 2024第四届餐饮与供应链专题展 邀 请 函郑州全国商品交易会&#xff08;简称郑交会&#xff09;是全国大型性经贸活动&#xff0c;一直秉承“政府指导&#xff0c;市场化运作”的模式&#xff0c;自1995年以来已成功举办了二十八届&#xff0c;是国内…

k8s多集群管理工具kubecm

文章目录 一、概述二、安装1、官网链接2、各平台安装2.1、MacOS2.2、Linux2.3、Windows 三、实例1、验证2、配置kubecm自动补全&#xff08;选做&#xff09;2.1、Bash2.2、Zsh2.3、fish2.4、PowerShell 3、创建存放kubeconfig文件的目录4、添加到 $HOME/.kube/config4.1、kube…