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

【后端面试总结】golang channel深入理解

在Go语言中,Channel是一种用于在goroutine之间进行通信和同步的重要机制。它提供了一种安全、类型安全的方式来传递数据,使得并发编程变得更加直观和简单。本文将详细介绍Golang中Channel的基本概念、创建与关闭、发送与接收操作,以及相关的使用场景和注意事项。另外,Channel本身也是Golang一个很核心的设计理念的良好体现,即:

Do not communicate by sharing memory; instead, share memory by communicating.

( 来源:Share Memory By Communicating - The Go Programming Language)

Golang的Channel基本介绍

Channel的基本概念

Channel是Go语言中的一种特殊类型,它像一个队列一样,遵循先进先出(FIFO)的原则,确保数据的顺序性。每个Channel都有一个指定的类型,只能传递相同类型的数据。Channel是并发安全的,允许多个goroutine同时读写,而不会引发数据竞争。

Channel的主要作用是实现goroutine之间的通信和同步。通过Channel,一个goroutine可以发送数据到另一个goroutine,从而实现数据的交换和共享。

Channel的创建与关闭

在Go中,可以使用内置的make函数来创建一个Channel。创建Channel时需要指定其传递的数据类型,并可以选择性地指定缓冲区大小。

// 创建一个无缓冲的Channel
ch1 := make(chan int) 
// 创建一个容量为10的缓冲Channel
ch2 := make(chan int, 10)

当不再需要向Channel发送数据,并且已经接收完所有数据时,应该关闭Channel。关闭Channel使用close函数。关闭后的Channel不能再发送数据,但可以继续接收已发送的数据,直到Channel为空。

close(ch1)

需要注意的是,关闭一个已经关闭的Channel会引发panic。

Channel的发送与接收操作

Channel的发送和接收操作使用操作符。发送数据到Channel使用ch 语法,从Channel接收数据使用value := 语法。

默认情况下,Channel的发送和接收操作都是阻塞的。即,在发送数据到Channel时,如果接收方没有准备好接收,发送方会被阻塞;同样,在从Channel接收数据时,如果发送方没有发送数据,接收方也会被阻塞。这种阻塞行为可以用于实现同步和协调。

如果需要实现非阻塞的发送和接收操作,可以使用select语句结合default子句。

Channel的使用场景

Channel在并发编程中有广泛的应用场景,包括但不限于:

  1. 消息传递
  2. Channel可以用于在不同的goroutine之间传递数据,实现基本的数据传输。
  3. 任务分发
  4. 可以将任务分发到多个goroutine中并行处理,每个goroutine处理完成后将结果发送回主goroutine或另一个处理结果的goroutine。
  5. 事件通知
  6. Channel可以用于实现事件的发布和订阅模式,当一个事件发生时,通过Channel将事件通知给所有订阅者。
  7. 同步信号
  8. 可以使用Channel作为信号量,当条件满足时,通过Channel发送一个信号,接收方收到信号后继续执行。
  9. 控制并发任务的启动和结束
  10. 通过Channel可以协调多个goroutine的启动和结束,确保它们按照预定的顺序执行。
  11. 限制并发数
  12. 可以使用带有缓冲的Channel来限制同时运行的goroutine数量。
  13. 同步操作
  14. 可以使用Channel来同步多个操作,确保它们按照预定的顺序进行。
  15. 异步处理
  16. Channel支持异步处理模式,即发送方发送数据后不需要等待接收方处理完成即可继续执行其他任务。

Channel实现原理

chan 使用 hchan 表示,它的传参与赋值始终都是指针形式,每个 hchan 对象代表着一个 chan。

  • hchan 中包含一个缓冲区 buf,它表示已经发送但是还未被接收的数据缓存。buf 的大小由创建 chan 时的参数来决定。qcount 表示当前缓冲区中有效数据的总量,dataqsiz 表示缓冲区的大小,对于无缓冲区通道而言 dataqsiz 的值为 0。如果 qcount 和 dataqsiz 的值相同,则表示缓冲区用完了。
  • 缓冲区表示的是一个环形队列 (如果你不熟悉环形队列,可以看一下 https://www.geeksforgeeks.org/circular-queue-set-1-introduction-array-implementation/)。其中 sendx 表示下一个发送的地址,recvx 表示下一个接收的地址。
  • recvq 表示等待接收的 sudog 列表,一个接收语句执行时,如果缓冲区没有数据而且当前没有别的发送者在等待,那么执行者 goroutine 会被挂起,并且将对应的 sudog 对象放到 recvq 中。
  • sendq 类似于 recvq,一个发送语句执行时,如果缓冲区已经满了,而且没有接收者在等待,那么执行者 goroutine 会被挂起,并且将对应的 sudog 放到 sendq 中。
  • closed 表示通道是否已经被关闭,0 代表没有被关闭,非 0 值代表已经被关闭。
  • lock 用于对 hchan 加锁

hchan 则是 channel 在 golang 中的内部实现。其定义如下:

type hchan struct {qcount   uint           // buffer 中已放入的元素个数dataqsiz uint           // 用户构造 channel 时指定的 buf 大小buf      unsafe.Pointer // bufferelemsize uint16         // buffer 中每个元素的大小closed   uint32         // channel 是否关闭,== 0 代表未 closedelemtype *_type         // channel 元素的类型信息sendx    uint           // buffer 中已发送的索引位置 send indexrecvx    uint           // buffer 中已接收的索引位置 receive indexrecvq    waitq          // 等待接收的 goroutine  list of recv waiterssendq    waitq          // 等待发送的 goroutine list of send waiterslock mutex
}

hchan 中的所有属性大致可以分为三类:

  1. buffer 相关的属性。例如 buf、dataqsiz、qcount 等。 当 channel 的缓冲区大小不为 0 时,buffer 中存放了待接收的数据。使用 ring buffer 实现。
  2. waitq 相关的属性,可以理解为是一个 FIFO 的标准队列。其中 recvq 中是正在等待接收数据的 goroutine,sendq 中是等待发送数据的 goroutine。waitq 使用双向链表实现。
  3. 其他属性,例如 lock、elemtype、closed 等。

channel 的 ring buffer 实现

channel 中使用了 ring buffer(环形缓冲区) 来缓存写入的数据。ring buffer 有很多好处,而且非常适合用来实现 FIFO 式的固定长度队列。

在 channel 中,ring buffer 的实现如下:

hchan 中有两个与 buffer 相关的变量: recvx 和 sendx。其中 sendx 表示 buffer 中可写的 index, recvx 表示 buffer 中可读的 index。 从 recvx 到 sendx 之间的元素,表示已正常存放入 buffer 中的数据。

我们可以直接使用 buf[recvx] 来读取到队列的第一个元素,使用 buf[sendx] = x 来将元素放到队尾。

数据发送:

发送数据分三种情况:

  • 有 goroutine 阻塞在 channel 上,此时 hchan.buf 为空:直接将数据发送给该 goroutine。
  • 当前 hchan.buf 还有可用空间:将数据放到 buffer 里面。
  • 当前 hchan.buf 已满:阻塞当前 goroutine。

第一种情况如下。从当前 channel 的等待队列中取出等待的 goroutine,然后调用 send。goready 负责唤醒 goroutine。

第二种情况比较简单。通过比较 qcount 和 dataqsiz 来判断 hchan.buf 是否还有可用空间。除此之后还需要调整一下 sendx 和 qcount。

数据读取:

从nil channel读取会抛异常。

从 closed channel 接收数据,如果 channel 中还有数据,接着走下面的流程。如果已经没有数据了,则返回默认值。使用 ok-idiom 方式读取的时候,第二个参数返回 false。

当前有发送 goroutine 阻塞在 channel 上,buf 已满:

如果buf size是0,则直接从sender读,否则读取队列的头

lock(&c.lock)if sg := c.sendq.dequeue(); sg != nil {// Found a waiting sender. If buffer is size 0, receive value// directly from sender. Otherwise, receive from head of queue// and add sender's value to the tail of the queue (both map to// the same buffer slot because the queue is full).recv(c, sg, ep, func() { unlock(&c.lock) }, 3)return true, true
}

buf 中有可用数据:

if c.qcount > 0 {// Receive directly from queueqp := chanbuf(c, c.recvx)if raceenabled {raceacquire(qp)racerelease(qp)}if ep != nil {typedmemmove(c.elemtype, ep, qp)}typedmemclr(c.elemtype, qp)c.recvx++if c.recvx == c.dataqsiz {c.recvx = 0}c.qcount--unlock(&c.lock)return true, true
}

buf为空,阻塞

无缓冲的通道只有当发送方和接收方都准备好时才会传送数据,否则准备好的一方将会被阻塞。

有缓存的channel区别在于只有当缓冲区被填满时,才会阻塞发送者,只有当缓冲区为空时才会阻塞接受者。

关闭channel的操作原则上应该由发送者完成,因为如果仍然向一个已关闭的channel发送数据,会导致程序抛出panic。而如果由接受者关闭channel,则会遇到这个风险。

从一个已关闭的channel中读取数据不会报错。只不过需要注意的是,接受者就不会被一个已关闭的channel的阻塞。而且接受者从关闭的channel中仍然可以读取出数据,只不过是这个channel的数据类型的默认值。我们可以通过指定接受状态位来观察接受的数据是否是从一个已关闭的channel所发送出来的数据。

有缓冲channel和无缓冲channel的应用场景

  • 无缓冲channel:同步消息
  • 有缓冲channel:异步消息

为什么Channel会被设计成向已经关闭的channel发送数据会引发panic

Channel 的基本特性和关闭机制

首先,我们需要了解 Channel 的基本特性和关闭机制。Channel 在 Go 中是一个类型安全的队列,它支持两个基本操作:发送(send)和接收(receive)。发送操作将数据放入 Channel,而接收操作从 Channel 中取出数据。通过关闭 Channel(使用 close 函数),发送者可以通知接收者没有更多的数据将被发送。

关闭 Channel 是一个单向操作,意味着一旦 Channel 被关闭,就不能再向其中发送数据。这是 Channel 设计中的一个关键原则,它确保了数据的发送和接收之间的同步和一致性。

为什么向已关闭的 Channel 写数据会引发 Panic?

向一个已经关闭的 Channel 发送数据会引发 panic,这主要是出于以下几个原因:

  1. 保持数据一致性:一旦 Channel 被关闭,接收者应该能够安全地假设不会有更多的数据被发送。如果允许向已关闭的 Channel 发送数据,这将会破坏这种一致性,导致接收者无法准确地判断 Channel 的状态,从而可能引发数据竞争或其他并发问题。
  2. 避免资源泄漏:Channel 的关闭通常意味着与其相关的资源(如内存和 goroutine)可以被释放。如果允许向已关闭的 Channel 发送数据,这些资源可能无法被及时释放,从而导致资源泄漏。
  3. 简化错误处理:通过引发 panic,Go 语言强制开发者在编写代码时处理向已关闭的 Channel 发送数据的情况。这有助于开发者在开发阶段就发现并修复潜在的错误,从而提高程序的健壮性和稳定性。
  4. 符合直观预期:从直觉上讲,向一个已经关闭的通信管道发送数据是不合理的。Go 语言的设计哲学倾向于直观和简洁,因此将这种操作定义为 panic 符合大多数开发者的直观预期。

相关文章:

【后端面试总结】golang channel深入理解

在Go语言中,Channel是一种用于在goroutine之间进行通信和同步的重要机制。它提供了一种安全、类型安全的方式来传递数据,使得并发编程变得更加直观和简单。本文将详细介绍Golang中Channel的基本概念、创建与关闭、发送与接收操作,以及相关的使…...

lobeChat安装

一、安装Node.js version > v18.17.0 二、下载 cd F:\AITOOLS\LobeChat git clone https://github.com/lobehub/lobe-chat.git (下载要是失败就手动下:https://codeload.github.com/lobehub/lobe-chat/zip/refs/heads/main) npm install …...

OpenCV 简介与安装方法

大家好啊,我是董董灿。 如果你在做计算机视觉相关的工作,肯定少不了使用 OpenCV 库。 在《计算机视觉专栏》的传统计算机视觉部分,我曾经使用 OpenCV 进行了很多图像的处理,比如边缘检测。 刚好最近在整理一份文稿,…...

力扣刷题TOP101:14.BM16 删除有序链表中重复的元素-II

目录: 目的 思路 复杂度 记忆秘诀 python代码 目的 1→1→2→3→3 删除重复后变成2。 思路 这个任务是删除链表里重复的节点包含本身。可以看成是一个抽奖活动的系统升级。某人通过多种方式报名(节点不同),后台数据检测到这些…...

Hadoop生态圈框架部署 伪集群版(四)- Zookeeper单机部署

文章目录 前言一、Zookeeper单机部署(手动部署)1. 下载Zookeeper安装包到Linux2. 解压zookeeper安装包3. 配置zookeeper配置文件4. 配置Zookeeper系统环境变量5. 启动Zookeeper6. 停止Zookeeper在这里插入图片描述 注意 前言 本文将详细介绍Zookeeper的…...

【Linux】文件

声明:以下内容均学习自《Linux就该这么学》一书 1、文件权限及归属 对目录文件来说,“可读”表示能够读取目录内的文件列表;“可写”表示能够在目录内新增、删除、重命名文件;“可执行”表示能够进入该目录。 文件类型区分 -普通…...

仿真键盘输入遇到Edge环境不识别 回车符如何处理

这个问题我也是最近才遇到,可能现在大家都喜欢用新架构,基于网页来写应用管理软件。 当遇到Edge环境下,文本框不识别回车符如何处理,根据笔者经验可通过配置Edge 基于键盘管理设置来解决这个事情。如图 即在Edge浏览器环境下&…...

Python 列表操作详解

Python 列表操作详解 在 Python 中,列表(list)是一种用于存储有序集合的数据结构。列表可以包含各种类型的数据,如整数、浮点数、字符串等,甚至可以包含其他列表(这称为嵌套列表)。 示例列表 …...

Git操作学习2

1.使用git rm删除文件 查看文件夹的内容 ls -lr 删除文件rm 文件名 但是此时只删了工作区的文件,仓库还没有删 可以再使用git add更新提交给仓库 也可以直接通过git rm 删除仓库里面的文件 工作区也删除了 暂存区也删除了 最后记得提交 否则删除的文件在版本库还…...

Spring Event 监听与异步设置:深入解析与应用场景

在开发中,事件驱动编程(Event-Driven Programming)是一种常见的编程模式,Spring 提供了强大的事件机制,使得我们可以通过 EventListener 或 ApplicationListener 来监听和处理应用中的各种事件。这种机制不仅使得应用架…...

百度木木浆测试

本程序测试识别图片的文字 import cv2 from paddleocr import PaddleOCR, draw_ocr from matplotlib import pyplot as plt # 加载PaddleOCR模型,这里你可以根据需要选择语言和模型路径 ocr PaddleOCR(use_gpuFalse, langch) # 假设我们识别中文字符&#xff0c…...

视频监控集中管理方案设计:Liveweb视频汇聚方案技术特点与应用

随着科技的发展,视频监控平台在各个领域的应用越来越广泛。然而,当前的视频监控平台仍存在一些问题,如视频质量不高、监控范围有限、智能化程度不够等。这些问题不仅影响了监控效果,也制约了视频监控平台的发展。 为了解决这些问…...

剑指offer(专项突破)---字符串

总目录:剑指offer(专项突破)---目录-CSDN博客 1.字符串的基本知识 C语言中: 函数名功能描述strcpy(s1, s2)将字符串s2复制到字符串s1中,包括结束符\0,要求s1有足够空间容纳s2的内容。strncpy(s1, s2, n)…...

Zygote启动流程(AndroidV)

一:背景 众所周知,Android应用及system_server基本都是由zygote fork出来的,那么zygote是如何启动的、又是如何接收fork进程的请求,接下来一步步揭秘。 二:启动流程 init进程是Android系统启动时,启动的第一…...

Web 毕设篇-适合小白、初级入门练手的 Spring Boot Web 毕业设计项目:智行无忧停车场管理系统(前后端源码 + 数据库 sql 脚本)

🔥博客主页: 【小扳_-CSDN博客】 ❤感谢大家点赞👍收藏⭐评论✍ 文章目录 1.0 项目介绍 1.1 项目功能 2.0 用户登录功能 3.0 首页界面 4.0 车辆信息管理功能 5.0 停车位管理功能 6.0 入场登记管理功能 7.0 预约管理功能 8.0 收费规则功能 9.0…...

岩体力学的材质-力学等属性的自动划分.

#背景: 在力学求解过程中,我们往往会对目标物体进行网格划分, 那么如何做到自动完成这个过程呢? 这里使用岩体力学中的地下岩层进行举例,这里只是简单的导入了4种界面, 复杂的可以一次性导入几十种界面,都可以计算(你能分多细,这个计算方式就可以帮你分层多细) 这里我只是导…...

注解 实现原理 详解

Java 注解实现原理详解 注解(Annotation)是 Java 提供的一种元数据机制,用于为代码元素(类、方法、字段、参数等)添加额外的信息。注解不会直接影响程序逻辑,但可以通过 工具(如编译器、运行时…...

第4章 陷入与系统调用

有三种类型的事件会让CPU停止正常执行的指令,强制切换到指定的代码,处理这些事件。一种是系统调用,当用户程序执行ecall指令来让内核为它做一些事。另一种是异常:一个指令(用户或内核)做了一些非法的事&…...

项目基于oshi库快速搭建一个cpu监控面板

后端&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.github.oshi</groupId><artifactId>oshi-…...

力扣C语言刷题记录 (二)移除元素

给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不等于 val 的元素数量为 k&#xff0c;要通过此题&#xff0c;您需要执行以下操作&#xff1a; 更改…...

多模态大语言模型的对比

简介 文章主要对比了包括 VideoLLaMA 2 、CogVLM2-video 、MiniCPM-V等模型 目前主流的多模态视觉问答大模型&#xff0c;大部分采用视觉编码器、大语言模型、图像到文本特征的投影模块 目录 简介1. VideoLLaMA 21.1 网络结构1.2 STC connector具体的架构 2. MiniCPM-V 2.62.…...

关于最近od机考中--树

题目 树按照层级遍历获取非叶子结点&#xff0c;然后将非叶子结点以后序遍历打印。 eg 图解 只需要将1&#xff0c;3&#xff0c;4&#xff0c;2进行后序遍历打印&#xff1a;既左-右-中方式打印 最后结果如&#xff1a;2&#xff0c;3&#xff0c;4&#xff0c;1。 思路&a…...

基数排序(代码+注释)

#include <stdio.h> #include <stdlib.h>// 获取数组中的最大值 int GetMax(int* a, int n) {int max a[0];for (int i 1; i < n; i) {if (a[i] > max) {max a[i];}}return max; }// 对数组按照某个位数进行计数排序 void CountingSortForRadix(int* a, i…...

NLP 相关知识的构成

自然语言处理&#xff08;Natural Language Processing, NLP&#xff09; 自然语言处理相关知识 自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;什么是自然语言处理&#xff1f;自然语言处理的构成1. 基本术语1.1 分词&#xff08;Segmentation&#x…...

算力100问☞第20问:GPU算力的影响因素有哪些?

影响因素1&#xff1a;核心数量 GPU中的计算核心数量是决定其算力的关键因素之一。更多的计算核心意味着可以同时处理更多的数据和任务&#xff0c;从而提高整体的计算效率。例如&#xff0c;GPU里面的计算核心就好像是工厂里的工人。工人数量越多&#xff0c;同时干活儿的也就…...

C语言柔性数组

在C语言中&#xff0c;结构体定义数组指定长度0&#xff0c;sizeof时候不计入占用&#xff0c;实际分配时候占用为准&#xff01; 也许你从来没有听说过柔性数组的概念&#xff0c;但其确实存在。C99规定&#xff1a;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就…...

TensorFlow与PyTorch对比:哪个更适合初学者?

小贴士: 不必着急,慢慢消化每一部分。有问题就查阅示例,实践是最好的老师!别忘了,选择合适的框架才是王道!💻🔍 本文全面对比了 TensorFlow 与 PyTorch 两大深度学习框架,详细分析了它们的特点、优势及适用场景,帮助初学者做出框架选择。内容包含框架背景、代码示例…...

Windows 11 如何配置node.js

一&#xff0c;官网下载 官网首页 下载最新LTS版本&#xff0c;比较稳定&#xff0c;如果想探索更新的版本去探索新的nodejs功能。 1. 下载完成后&#xff0c;双击运行程序&#xff0c;点击next 2. 勾选接受协议&#xff0c;点击next 3. 选择自己的安装路径&#xff08;默认是…...

std::reverse_iterator

std::reverse_iterator 是 C 标准库中的一个迭代器适配器&#xff08;iterator adapter&#xff09;&#xff0c;它允许你以反向顺序遍历容器或序列。这个适配器通过封装一个基础迭代器&#xff08;通常是正向迭代器&#xff09;并提供反向的递增&#xff08;&#xff09;和递减…...

On-Chip-Network之router微架构的物理实现

Low-Power Microarchitecture 自20世纪90年代以来&#xff0c;功耗一直是嵌入式芯片和高性能芯片面临的一个挑战。自2000年代中期以来&#xff0c;它已经成为大多数设计的主要约束。多核解决了功耗问题&#xff0c;由此产生的communication substrate&#xff0c;namely the on…...

学习threejs,使用canvas更新纹理

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️Texture 贴图 二、&#x1…...

CSS 选择器的优先级

一、基本概念 CSS 选择器的优先级决定了在样式冲突时&#xff0c;哪个样式规则将被应用到 HTML 元素上。通过理解 CSS 选择器的优先级&#xff0c;可以更好地控制网页元素的样式&#xff0c;避免样式冲突。 二、优先级计算规则 1. 内联样式 内联样式具有最高的优先级。 &l…...

如何将python项目导出为docker镜像

如何将python项目导出为docker镜像 前提条件步骤 1: 创建并准备 Python 项目步骤 2: 创建 `setup.py`步骤 3: 打包项目步骤 4: 创建 Dockerfile步骤 5: 构建 Docker 镜像步骤 6: 运行 Docker 容器步骤 7: 保存修改并继续开发总结要将修改后的Python代码导出为 .tar.gz 格式,并…...

微信 创建小程序码-有数量限制

获取小程序码&#xff1a;小程序码为圆图&#xff0c;有数量限制。 目录 文档 接口地址 功能描述 注意事项 请求参数 对接 获取小程序码 调用获取 小程序码示例 总结 文档 接口地址 https://api.weixin.qq.com/wxa/getwxacode?access_tokenaccess_token 功能描述 …...

桶排序(代码+注释)

#include <stdio.h> #include <stdlib.h>// 定义桶的结构 typedef struct Bucket {int* data; // 动态数组int count; // 当前存储的元素个数int capacity; // 桶的容量 } Bucket;// 初始化桶 void InitBucket(Bucket* bucket) {bucket->capacity 10; // 初…...

Python从入门到入狱

Python是从入门到入狱&#xff1f;这个充满调侃意味的说法在程序员圈子里流传甚广。表面看&#xff0c;它似乎是在嘲笑这门语言从简单易学到深陷麻烦的巨大反差&#xff0c;实际上却隐藏着很多值得深思的问题。要解读这个话题&#xff0c;得从Python的特点、使用场景以及潜在风…...

图像模糊处理

图像模糊处理 C语言实现C实现Java实现Python实现 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 给定n行m列的图像各像素点的灰度值&#xff0c;要求用如下方法对其进行模糊化处理&#xff1a; 1 四周最外侧的像素点灰度值不变&#xff1b…...

全面UI组件库Telerik 2024 Q4全新发布——官方宣布支持.NET 9

Telerik DevCraft包含一个完整的产品栈来构建您下一个Web、移动和桌面应用程序。它使用HTML和每个.NET平台的UI库&#xff0c;加快开发速度。Telerik DevCraft提供最完整的工具箱&#xff0c;用于构建现代和面向未来的业务应用程序&#xff0c;目前提供UI for ASP.NET MVC、Ken…...

请求响应:常见参数接收及封装(Json参数及路径参数)

Json参数 Json格式的数据具有轻量级、易于阅读和编写、易于解析等诸多优点。在前后端交互时&#xff0c;大部分情况下请求体中的数据会以JSON格式进行传递。前端的请求在请求体中携带了Json格式数据&#xff0c;后端程序需要对其进行解析并封装使用&#xff0c;而接收Json参数…...

Doge东哥wordpress主题

Doge东哥wordpress主题是一款专为中小型企业设计的WordPress外贸网站模板&#xff0c;它以其现代、专业且用户友好的界面&#xff0c;为企业提供了一个展示产品和服务的理想平台。以下是对该模板的详细描述&#xff1a; 首页设计概览 首页的设计简洁而不失大气&#xff0c;顶…...

深度学习常用指标

1. 混淆矩阵&#xff08;误差矩阵&#xff09; 2. 准确率&#xff08;overall accuracy&#xff09; 代表了所有预测正确的样本占所有预测样本总数的比例 这里分类正确代表了正样本被正确分类为正样本&#xff0c;负样本被正确分类为负样本 3. 平均精度&#xff08;average…...

AMR移动机器人赋能制造业仓储自动化升级

在当今制造业的激烈竞争中&#xff0c;智能化、数字化已成为企业转型升级的关键路径。一家制造业巨头&#xff0c;凭借其庞大的生产体系和多个仓库资源&#xff0c;正以前所未有的决心和行动力&#xff0c;在制造业智能化浪潮中勇立潮头&#xff0c;开启了降本增效的新篇章。这…...

显卡(Graphics Processing Unit,GPU)比特币挖矿

1. 比特币挖矿基本原理 比特币挖矿是通过参与比特币网络的共识机制——工作量证明&#xff08;Proof of Work, PoW&#xff09; 来完成的。具体来说&#xff0c;矿工通过不断尝试不同的哈希值&#xff0c;以解决一个难度逐渐增大的数学问题&#xff0c;从而验证交易并获得比特…...

11.7【miniob】【debug】

这里的vector是实际值&#xff0c;而relation是指针&#xff0c;所以要解引用&#xff0c;*$1&#xff0c;并在最后调用其析构函数 emplace_back 和 push_back 都是用于在容器&#xff08;如 std::vector&#xff09;的末尾添加元素的方法&#xff0c;但它们的工作方式有所不同…...

力扣第89题 格雷编码

题目描述 格雷编码序列是一个二进制数字序列&#xff0c;其中的每两个相邻的数字只有一个二进制位不同。给定一个整数 n&#xff0c;表示格雷编码的位数&#xff0c;要求返回 n 位的格雷编码序列。 示例 1 输入&#xff1a; n 2输出&#xff1a; [0, 1, 3, 2]解释&#x…...

ros sensor_msgs::Imu详细介绍 Eigen::Vector3d 详细介绍

1.ros sensor_msgs::Imu详细介绍 sensor_msgs::Imu 是 ROS&#xff08;Robot Operating System&#xff09;中用于表示惯性测量单元&#xff08;IMU&#xff09;数据的消息类型。IMU 是一种传感器&#xff0c;通常用于测量物体的线性加速度、角速度和方向信息。以下是 sensor_…...

【ArcGIS微课1000例】0133:二维建筑物依据高度生成三维模型

拓展阅读:【ArcGIS Pro微课1000例】0032:创建具有指定高程Z值的矢量数据 文章目录 一、二维面要素拉伸实现三维显示二、依据高度实现要素转3D一、二维面要素拉伸实现三维显示 打开ArcScene软件,加载实验配套数据0133.rar中的建筑物.shp数据,如下图: 数据属性表中的Z为建筑…...

虚拟内存的意义

1.什么是虚拟内存 虚拟内存的基本原理是将物理内存与磁盘空间组合使用&#xff0c;将正在执行的程序的部分数据和代码加载到物理内存中&#xff0c;而不是全部加载。当程序需要访问未加载到内存的部分时&#xff0c;操作系统会将相关数据从磁盘中加载到内存中 2.为了解决什么…...

h5 sqlite 操作封装

参考文档 错误码 // 数据库名称 const namesjk "sl" // 存储路径 const path _doc/${name}.db/** 基本操作* 查询数据库连接状态 isOpenDatabase * 无参数* 返回 true false* * * 关闭数据库 closeDatabase* 无参数* Promise 成功/失败* * * …...

Git 详解

Git 详解 Git 是一个分布式版本控制系统&#xff0c;用于高效地管理项目代码的版本历史。它是目前最流行的版本控制工具之一&#xff0c;广泛应用于软件开发领域。Git 的分布式架构允许开发者在本地进行代码的版本管理&#xff0c;并与远程仓库同步&#xff0c;实现团队协作。…...