【Go 基础】channel
Go 基础
channel
什么是channel,为什么它可以做到线程安全
Go 的设计思想就是:不要通过共享内存来通信,而是通过通信来共享内存。 前者就是传统的加锁,后者就是 channel。也即,channel 的主要目的就是在多任务间传递数据的,本身就是安全的。
- channel 是 Go 中的一个核心类型,它可以看作是一个管道,通过它并发核心单元就可以发送或者接收数据进行通讯。
- channel 也可以理解为一个先进先出队列,通过管道进行通信;
- 发送一个数据到 channel 和从 channel 中接收一个数据都是原子性的;
channel的生命周期状态有哪些
channel 存在 3 种状态:
- nil:未初始化的状态,只进行了声明,或者手动赋值为 nil
- active:正常的 channel,可以进行读写;
- closed:已关闭,注意已关闭的 channel,它的值也不是 nil
针对不同状态的 channel,进行关闭,发送数据以及接收数据,会有不同的情况:
操作 | 一个零值 nil 通道 | 一个非零值但已关闭通道 | 一个非零值且未关闭通道 |
---|---|---|---|
关闭 | 产生恐慌 | 产生恐慌 | 成功关闭 |
发送数据 | 永久阻塞 | 产生恐慌 | 阻塞或者成功发送 |
接收数据 | 永久阻塞 | 永不阻塞(会立即返回零值) | 阻塞或者成功接收 |
channel 的类型
channel 通常有以下三种类型:
- 同步 channel:不需要缓冲区,发送方会直接将数据交给接收方;
- 异步 channel:基于环形缓存的传统生产者消费者模型;
- chan struct{}:这是专门用于协程间通信的标准信号,因为 struct{} 不占用内存空间,所以用的比较多;
Goroutine 和 channel 的作用分别是什么
这里可以先简单说下,进程、线程以及协程之间的关系。
进程是内存资源和 CPU 调度的执行单元。为了有效利用多核处理器的优势,将进程进一步细分,允许一个进程中存在多个线程,这多个线程还是共享同一片内存空间,但 CPU 调度的最小单元变成了线程。
而协程,可以看作是轻量级线程。但是,和线程不同的是,线程的切换是由操作系统控制的,而协程的切换是由用户控制的。
Go 中的 Goroutine 就是协程,可以实现并行,多个协程可以在多个处理器同时跑。而协程同一时刻只能在一个处理器上跑。多个 Goroutine 之间的通信就是通过 channel,而协程的通信是通过 yield 和 resume() 操作。
在 Golang 中 channel 是 goroutinues 之间进⾏通信的渠道。
可以把 channel 形象⽐喻为⼯⼚⾥的传送带,⼀头的⽣产者 goroutine 往传输带放东⻄,另⼀头的消费者 goroutinue 则从输送带取东⻄。channel 实际上是⼀个有类型的消息队列,遵循先进先出的特点。
goroutine 的使用
只需要在函数的调用前面加 go 关键字,就可以启动协程了:
func main() {for i:=1;i<5;i++ {go func(i int) {fmt.Println(i)}(i)}// 停歇5s,保证打印全部结束time.Sleep(5*time.Second)
}
上面的代码中,启动了 5 个 goroutine,再加上 main 函数的主 goroutine,一共 6 个 goroutine。由于 goroutine 类似于“守护线程”,是异步执行的。如果主 goroutine 不等待,程序可能就不会有打印输出了。
channel 的使用
-
channel 的操作符号
ch <- data 表示 data 被发送给 channel ch ;
data <- ch 表示从 channel ch 取⼀个值,然后赋给 data;
-
阻塞式 channel
channel 默认是没有缓冲区的,也即,通信是阻塞的。send 操作必须等到有消费者 accept 才算完成。
func main() {ch1 := make(chan int)go pump(ch1) // pump hangsfmt.Println(<-ch1) // prints only 1 }func pump(ch chan int) {for i := 1; ; i++ {ch <- i} }
在函数 pump() ⾥的 channel 在接受到第⼀个元素后就被阻塞了,直到主 goroutinue 取⾛了数据。最终channel 阻塞在接受第⼆个元素,程序只打印 1。
没有缓冲的 channel 只能容纳⼀个元素,⽽带有缓冲 channel 则可以⾮阻塞容纳 N 个元素。发送数据到缓冲 channel 不会被阻塞,除⾮channel已满;同样的,从缓冲 channel 取数据也不会被阻塞,除⾮ channel 空了。
Go 中 channel 的实现
前文其实就一直有提到了:channel 是 Go 中 goroutines 之间的信息传递媒介,通过共享通信,来实现共享内存。
goroutine 通过使⽤ channel 传递数据,⼀个会向 Channel 中发送数据,另⼀个会从 Channel 中接收数据,它们两者能够独⽴运⾏并不存在直接关联,但是能通过 Channel 间接完成通信。
channel 的收发操作均遵循来先进先出的设计:
- 先从 channel 读取数据的 goroutine 会先接收到数据
- 先往 channel 发送数据的 goroutine 会得到先发送数据的权利
channel 在 runtime 中的具体实现
在 runtime.hchan 中定义了 channel:
type hchan struct {qcount uint // 当前队列⾥还剩余元素个数dataqsiz uint // 环形队列⻓度,即缓冲区的⼤⼩,即make(chan T,N)中的Nbuf unsafe.Pointer // 环形队列指针elemsize uint16 // 每个元素的⼤⼩closed uint32 // 标识当前通道是否处于关闭状态,创建通道后,该字段设置0,即打开通道;通道调⽤close将其设置为1,通道关闭elemtype *_type // 元素类型,⽤于数据传递过程中的赋值sendx uint // 环形缓冲区的状态字段,它只是缓冲区的当前索引-⽀持数组,它可以从中发送数据recvx uint // 环形缓冲区的状态字段,它只是缓冲区当前索引-⽀持数 组,它可以从中接受数据recvq waitq // 等待读消息的goroutine队列sendq waitq // 等待写消息的goroutine队列// lock protects all fields in hchan, as well as several// fields in sudogs blocked on this channel.//// Do not change another G's status while holding this lock// (in particular, do not ready a G), as this can deadlock// with stack shrinking.lock mutex // 互斥锁,为每个读写操作锁定通道,因为发送和接受必须是互斥操作
}
type waitq struct {first *sudoglast *sudog
}
其中,hchan 结构体中有五个字段是构建底层的循环队列:
- qcount:channel 中剩余元素的个数
- dataqsiz:channel 中循环队列的长度
- buf:channel 的缓冲区数据指针
- sendx:channel 的发送操作处理到的位置
- recvx:channel 的接收操作处理到的位置
elemsize 和 elemtype 分别表示当前 channel 能够收发的元素类型和大小。
sendq 和 recvq 存储了当前 channel 由于缓冲区不足而阻塞的 goroutine 列表,这些等待队列使用双向链表 runtime.waitq 表示,链表中所有的元素都是 runtime.sudog 结构。
waitq 表示一个在等待队列中的 goroutine,该结构体存储了阻塞的相关信息以及两个分别指向前后 runtime.sudog 的指针。
创建 channel
runtime.makechan 和 runtime.makechan64 会根据传入的参数类型和缓冲区大小创建一个新的 channel 结构,其中后者用于处理缓冲区大小大于 2 的 32 次方的情况。
我们以 makechan 函数为例:
func makechan(t *chantype, size int) *hchan {elem := t.elem// compiler checks this but be safe.if elem.size >= 1<<16 {throw("makechan: invalid channel element type")}if hchanSize%maxAlign != 0 || elem.align > maxAlign {throw("makechan: bad alignment")}mem, overflow := math.MulUintptr(elem.size, uintptr(size))if overflow || mem > maxAlloc-hchanSize || size < 0 {panic(plainError("makechan: size out of range"))}// Hchan does not contain pointers interesting for GC when elements stored in buf do not contain pointers.// buf points into the same allocation, elemtype is persistent.// SudoG's are referenced from their owning thread so they can't be collected.// TODO(dvyukov,rlh): Rethink when collector can move allocated objects.var c *hchanswitch {case mem == 0:// Queue or element size is zero.c = (*hchan)(mallocgc(hchanSize, nil, true))// Race detector uses this location for synchronization.c.buf = c.raceaddr()case elem.ptrdata == 0:// Elements do not contain pointers.// Allocate hchan and buf in one call.c = (*hchan)(mallocgc(hchanSize+mem, nil, true))c.buf = add(unsafe.Pointer(c), hchanSize)default:// Elements contain pointers.c = new(hchan)c.buf = mallocgc(mem, elem, true)}c.elemsize = uint16(elem.size)c.elemtype = elemc.dataqsiz = uint(size)lockInit(&c.lock, lockRankHchan)if debugChan {print("makechan: chan=", c, "; elemsize=", elem.size, "; dataqsiz=", size, "\n")}return c
}
channel 中根据收发元素的类型和缓冲区的大小初始化 runtime.hchan 结构题和缓冲区:
arena 区域就是我们所谓的堆区,Go 动态分配的内存都是在这个区域,它把内存分割成 8KB 大小的页,一些页组合起来称为 mspan。
bitmap 区域标识 arena 区域哪些地址保存了对象,并且用 4bit 标志位表示对象是否包含指针、GC 标记信息。bitmap 中一个 byte 大小的内存对应 arena 区域中 4 个指针大小(指针大小为 8B)的内存,所以 bitmap 区域的大小是 512GB/(4*8B)=16GB。
此外,我们还可以看到 bitmap 的高地址部分指向 arena 区域的低地址部分,这里 bitmap 的地址是由高地址向低地址增长的。
spans 区域存放 mspan(是一些 arena 分割的页组合起来的内存管理基本单元)的指针,每个指针对应一页,所以 spans 区域的大小就是 512GB/8KB*8B=512MB。
除以 8KB 是计算 arena 区域的页数,而最后乘以 8 是计算 spans 区域所有指针的大小。创建 mspan 的时候,按页填充对应的 spans 区域,在回收 object 时,根据地址很容易就能找到它所属的 mspan。
相关文章:
【Go 基础】channel
Go 基础 channel 什么是channel,为什么它可以做到线程安全 Go 的设计思想就是:不要通过共享内存来通信,而是通过通信来共享内存。 前者就是传统的加锁,后者就是 channel。也即,channel 的主要目的就是在多任务间传递…...
长安汽车嵌入式面试题及参考答案
数据结构中的堆栈和编程中的堆栈有什么区别? 在数据结构中,堆栈是一种抽象的数据类型。它遵循后进先出(LIFO)的原则。从操作角度来看,有入栈(push)和出栈(pop)操作。例如…...
理解Linux的select、poll 和 epoll:从原理到应用场景
I/O 多路复用并不是什么新东西,select 早在 1983 年就出现了,poll 在 1997 年,epoll 是 2002 年的产物。面试题总爱问“多路复用多厉害?”其实它就是把轮询的锅甩给了操作系统,而操作系统不过是用 CPU 指令帮你完成事件…...
(一)Linux下安装NVIDIA驱动(操作记录)
目录 一、查看CUDA版本 1.输入nvidia-smi,查看驱动支持的最大CUDA版本,这里是11.6 2.输入nvcc --version,查看当前安装的CUDA版本,这里是11.3 二、卸载旧的NVIDIA驱动 1.卸载原有驱动 2.禁用nouveau(必须&#x…...
二分法篇——于上下边界的扭转压缩间,窥见正解辉映之光(2)
前言 上篇介绍了二分法的相关原理并结合具体题目进行讲解运用,本篇将加大难度,进一步强化对二分法的掌握。 一. 寻找峰值 1.1 题目链接:https://leetcode.cn/problems/find-peak-element/description/ 1.2 题目分析: 题目要求返回数组内…...
移动机器人课程建图实验-ROSbug汇总
问题1描述 $ rosrun robot_state_publisher robot_state_publisher [ERROR] [1733131886.474757207]: [registerPublisher] Failed to contact master at [localhost:11311]. Retrying...解决方案 这个错误信息表明 robot_state_publisher 节点无法联系到 ROS master。通常&…...
记录vite关于tailwindcss4.0-bate4出现margin[m-*]、padding[p-*]无法生效的问题。
环境如下: vite:5.4.10 tailwindcss: 4.0.0-beta.4 tailwindcss/vite: 4.0.0-beta.4 4.0默认的样式优先级比较低 如果使用了一些reset的css文件 那么很多样式会失效 例如:reset.css中 html, body, ul, li, h1, h2, h3, h4, h5, h6, dl, dt, dd, ol, i…...
WPF+MVVM案例实战与特效(三十)- 封装一个系统日志显示控件
文章目录 1、运行效果2、日志控件封装1、文件创建2、DisplayLogPanel.xaml 代码3、DisplayLogPanel.cs 代码4、数据模型5、枚举类型3、自定义控件使用1、LogPanelWindow.xaml2、LogPanelViewModel.cs4、总结1、运行效果 2、日志控件封装 1、文件创建 打开 Wpf_Examples ,在 …...
redis中jedis和lettuce pool的区别,那个更好,使用范围更广
在 Redis 的 Java 客户端中,Jedis 和 Lettuce 是两种最常用的客户端库,它们都支持连接池(JedisPool 和 Lettuce Connection Pool),但在设计和特性上有显著差异。下面我将详细对比它们的特点,帮助你更好地选择适合的库。 1. 同步 vs 异步 Jedis:是一个 同步 的 Redis 客…...
调试openai 星河大模型的记录:用tcpdump和ngrep抓包
在调试esp32开发板连星河大模型的时候,用requests连星河,怎么也调不通,想通过抓包,看看openai和自己写的到底有啥不一样。 结论:抓包抓到的太多,而且ssl 已经把一些信息都处理过了,看不到报文的…...
树莓派明明安装了opencv和numpy,却找不到
当然不止树莓派,配置python环境都可能存在这个问题 可能是因为安装的 numpy 或者 opencv 版本与 Python 的包路径不匹配。下面是问题的常见原因及解决方法:【方法一和二优先考虑】 原因分析 多版本 Python 环境冲突: 树莓派上可能有多个版本…...
【C++boost::asio网络编程】有关异步读写api的笔记
异步读写api 异步写操作async_write_someasync_send 异步读操作async_read_someasync_receive 定义一个Session类,主要是为了服务端专门为客户端服务创建的管理类 class Session { public:Session(std::shared_ptr<asio::ip::tcp::socket> socket);void Conn…...
github仓库自动同步到gitee
Github Actions是Github推出的自动化CI/CD的功能,我们将使用Github Actions让Github仓库同步到Gitee 同步的原理是利用 SSH 公私钥配对的方式拉取 Github 仓库的代码并推送到 Gitee 仓库中,所以我们需要以下几个步骤 生成 SSH 公私钥添加公钥添加私钥配…...
详解LinkedList中的底层实现
1.LinkedList的构造器 无参构造器 /*** Constructs an empty list.*/ public LinkedList() { } 构造Collection: 只要是 Collection 下的实现类都可以被 LinkedList 构造 // ? extends E: 只要是E的子类及E类型的类都可以使用 public LinkedList(Collection<? extends …...
HTML5动漫主题网站 天空之城 10页 html+css+设计报告成品项目模版
📂文章目录 一、📔网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站演示 五、⚙️网站代码 🧱HTML结构代码 💒CSS样式代码 六、🔧完整源码下载 七、📣更多 一、&#…...
【VSCode】如何修改左侧资源管理器字体大小
方法一 左下角的“设置”—> 选择“窗口” —> 找到 Zoom Level,一般1、2效果就挺大的,可以设置小数0.5、负数-1等,具体设置说明见下图: 这个有一点不好的是,不仅仅资源管理器字体变化,整个VSCode界面会跟着变…...
使用 Visual Studio 开发 Windows 服务
Windows 服务是一种后台运行的应用程序,可以在没有用户界面的情况下执行任务。以下是从概念到具体实现的详细说明。 1. 什么是 Windows 服务 Windows 服务是运行在 Windows 操作系统上的应用程序,具有以下特点: 后台运行:无需用…...
类型转换与IO流:C++世界的变形与交互之道
文章目录 前言🎄一、类型转换🎈1.1 隐式类型转换🎈1.2 显式类型转换🎁1. C 风格强制类型转换🎁2. C 类型转换操作符 🎈1.3 C 类型转换操作符详解🎁1. static_cast🎁2. dynamic_cast&…...
go的web框架介绍
Go 语言有许多优秀的 Web 框架,适用于不同类型的 Web 应用开发,涵盖从简单的 API 开发到复杂的微服务架构。以下是一些常见的 Go Web 框架: 1. Gin 简介:Gin 是一个高性能的 Go Web 框架,设计目标是让开发者能够以极…...
WPF+MVVM案例实战与特效(三十一)- 封装一个加载动画的自定义控件
文章目录 1、案例效果2、案例实现1、资源与文件创建2、自定义控件封装3、自定义控件使用4、总结1、案例效果 2、案例实现 在开发WPF应用程序时,我们常常需要一个灵活的加载动画控件,该控件可以根据窗口的大小自动调整其内部元素(如图片、边框和文本)的尺寸,并且能够通过简…...
cocos creator 3.8 抖音、字节跳动录制器 12
property(Node) luzhishijianDisplay: Node null!;//录制时间显示 property(Node) luzhikaishiBut: Node null!;//录制开始 property(Node) luzhijieshuBut: Node null!;//录制结束 luzhikaishiType: boolean false;//是否开始录制开始计时 gameluzhiTime: number 0;onLoa…...
汽车控制软件下载移动管家手机控车一键启动app
移动管家手机控制汽车系统是一款实现车辆远程智能控制的应用程序。通过下载并安装特定的APP,用户可以轻松实现以下功能:远程启动与熄火:无论身处何地,只要有网络,即可远程启动或熄火车辆,提前预冷或预…...
自由学习记录(28)
C# 中的流(Stream) 流(Stream)是用于读取和写入数据的抽象基类。 流表示从数据源读取或向数据源写入数据的矢量过程。 C# 中的流类是从 System.IO.Stream 基类派生的,提供了多种具体实现,每种实现都针对…...
HarmonyOS开发:关于签名信息配置详解
目录 前言 签名信息的重要性 签名的方式 自动化签名 1、连接真机 2、选择 手动签名 (一)生成密钥和证书请求文件 (二)申请调试证书 (三)注册调试设备 (四)申请调试Profil…...
react 组件双向绑定
1. 使用 state 实现双向绑定 对于双向绑定,需要同时处理表单元素的value属性(通过state来设置)和onChange事件(用于更新state)。 import { useState } from "react";const MyComponent () > {const [i…...
k8s api对象,CRD
在Kubernetes项目中,一个API对象在Etcd里的完整资源路径,是由:Group(API组)、Version(API版本)和Resource(API资源类型)三个部分组成 apiVersion: batch/v2alpha1 kind:…...
详解MyBatis之篇一
目录 MyBatis 定义 使用MyBatis操作数据库 创建项目 配置 演示 UserInfo.java UserInfoMapper UserInfoMapperTest 数据准备 自动生成测试类 运行结果 MyBatis 定义 MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避…...
uniapp连接mqtt频繁断开原因和解决方法
mqtt参考文档:MQTT.js 入门教程 | EMQ、MQTT.js 入门教程 - EMQX - 博客园 uniapp引用MQTT频繁断开的问题可能由于以下几个原因导致: 网络不稳定:频繁断开可能是由于网络不稳定导致的,可以尝试优化网络连接。 心跳机制问题&…...
网络安全内容整理二
网络嗅探技术 网络监听 网络监听,也称网络嗅探(Network Sniffing):在他方未察觉的情况下捕获其通信报文、通信内容的技术 网卡的工作模式: 1.广播模式(Broadcast Mode):网卡能够接收网络中的广播信息 2.组播模式(Multicast Mo…...
IDE解说
IDE(Integrated Development Environment,集成开发环境) 是一种集成了多种开发工具的软件应用程序,旨在简化软件开发过程。 IDE 通常包括代码编辑器、编译器或解释器、调试器、构建自动化工具和版本控制系统等组件。通过将这些工…...
安心护送转运平台小程序
安心护送转运平台小程序是一款基于FastAdminThinkPHPUniapp开发的非急救救护车租用转运平台小程序系统,可以根据运营者的业务提供类似短途接送救护服务,重症病人转运服务,长途跨省护送服务。...
mongodb文档字符串批量替换
【mongodb文档字符串批量替换脚本语句】 前言: 1、本方式对于数据量大的情况不适用,执行可能比较慢; 2、数据量大的情况,个人推荐代码层面解决,多线程替换更快: (1)写实体类的方式…...
模拟实现vector(非常详细)
模拟实现vector 1.基本概念2.vector()默认构造函数3.size()4.capacity()5.empty()6.reverse7.push_back()8.pop_back()9.operator[ ]10.resize()11.insert() 1.基本概念 上一节我们讲了vector的概念以及常用的接口,这一节我们讲一下它的实现,它的底层其实…...
证明直纹极小曲面是平面或者正螺旋面.
目录 证明直纹极小曲面是平面或者正螺旋面 证明直纹极小曲面是平面或者正螺旋面 证明:设极小直纹面 S S S的参数表示为 r ( u , v ) a ( u ) v c ( u ) . (u,v)\mathbf{a}(u)v\mathbf{c}(u). (u,v)a(u)vc(u).则 r u a ′ v c ′ , r v c , r u ∧ r v a ′ ∧…...
电子应用设计方案-34:智能镜子系统方案设计
智能镜子系统方案设计 一、引言 智能镜子作为一种新兴的智能设备,将传统镜子与现代科技相结合,为用户提供了丰富的信息展示和交互功能。它不仅可以作为普通镜子使用,还能够显示天气、新闻、日程安排等信息,甚至可以与智能家居设备…...
前端项目从开发到部署全流程介绍
一、项目初始化 创建项目目录 首先创建一个新的项目目录,例如my - front - end - project。使用命令mkdir my - front - end - project && cd my - front - end - project。 初始化项目 使用npm init或yarn init来初始化项目,这会生成一个packag…...
Vue3.0组件之间通信(defineProps 和 defineEmits 及 defineExpose)
前言: 一、父传子 defineProps二、子传父 defineEmits三、子组件暴露属性和方法给父组件 defineExpose四、依赖注入Provide / Inject 在 <script setup> 中必须使用 defineProps 和 defineEmits API 来声明 props 和 emits ,它们具备完整的类型推…...
多种平台上安装部署调试Open5GS(四)
OpenWRT 源码安装 UERANSIM 安装依赖openwrt源码安装cmake其他依赖准备UERANSIM安装测试验证Open5GS 是一个功能完善的开源5G项目,具备5G、4G核心网功能,最新代码支持R17标准, 本系列文章介绍Open5GS在x86、ARM平台上的安装部署方法,并通过搭建UERANSIN、商用5G基站和终端两…...
KST-3D01型胎儿超声仿真体模、吸声材料以及超声骨密度仪用定量试件介绍
一、KST-3D01型胎儿超声仿真体模 KST—3D01型胎儿超声体模,采用仿羊水环境中内置胎龄为7个月大仿胎儿设计。用于超声影像系统3D扫描演示装置表面轮廓呈现和3D重建。仿羊水超声影像呈暗回声(无回波)特性,仿胎儿超声影像呈对比明显…...
论文笔记-WWW2024-ClickPrompt
论文笔记-WWW2024-ClickPrompt: CTR Models are Strong Prompt Generators for Adapting Language Models to CTR Prediction ClickPrompt: CTR模型是大模型适配CTR预测任务的强大提示生成器摘要1.引言2.预备知识2.1传统CTR预测2.2基于PLM的CTR预测 3.方法3.1概述3.2模态转换3.…...
VTK中对于相机camera的设置
1. 相机的核心属性 在 VTK 中,vtkCamera 的核心属性有默认值。如果你不设置这些属性,相机会使用默认值来渲染场景。 Position(默认值:(0, 0, 1)): 默认情况下,相机位于 Z 轴正方向的 (0, 0, 1)…...
小程序解决大问题-物流系统磁盘爆满问题处理
晚上七点,煤矿调运的物流调度系统突然磁盘报名导致服务崩溃。系统用的是微服务,没有详细操作说明,也不敢动,运煤车辆排起了长队,只能联系厂家处理。好在经过30多分钟的处理,服务终于启动,系统运…...
OGRE 3D----5. OGRE和QML事件交互
在现代图形应用程序开发中,OGRE(Object-Oriented Graphics Rendering Engine)作为一个高性能的3D渲染引擎,广泛应用于游戏开发、虚拟现实和仿真等领域。而QML(Qt Modeling Language)则是Qt框架中的一种声明式语言,专注于设计用户界面。将OGRE与QML结合,可以充分利用OGR…...
docker搭建nginx
一. 直接启动nginx镜像 1. 下载nginx镜像 docker pull nginx 2. 运行镜像 docker run -p 8080:80 --name web -d nginx 3. 网址查看 xx.xx.xx.xx:8080 二. 挂在文件启动nginx镜像 1. 拷贝docker文件到本地 docker cp web:/etc/nginx/nginx.conf /root/data/config/nginx…...
Qt之样式表设置总结。。。持续更新
参考文章链接如下: Qt样式表之一:Qt样式表和盒子模型介绍 Qt样式表之二:QSS语法及常用样式 Qt样式表之三:实现按钮三态效果的三种方法 Qt样式表之一:QSS名词解释 Qt样式表之二:常用控件qss Qt样式表之三:QSS奇技淫巧 样式表介绍 Qt样式表是一个可以自定义部件外观的十…...
若依项目源码阅读
源码阅读 前端代码分析 代码生成器生成的前端代码有两个,分别是course.js用于向后端发送ajax请求的接口代码,另一个是index.vue,用于在浏览器展示课程管理的视图组件。前端的代码是基于vue3elementplus。 template用于展示前端组件别的标签…...
Ubuntu20.04运行R-VIO2
目录 1.环境配置2.构建项目3. 运行 VIO 模式4.结果图 1.环境配置 CMakeLists.txt中 C 使用 14、opencv使用4 2.构建项目 克隆代码库: 在终端中执行以下命令克隆项目:git clone https://github.com/rpng/R-VIO2.git编译项目: 使用 catkin_m…...
【Python运维】容器管理新手入门:使用Python的docker-py库实现Docker容器管理与监控
《Python OpenCV从菜鸟到高手》带你进入图像处理与计算机视觉的大门! 解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 随着容器技术的广泛应用,Docker已经成为开发和运维中的标准工具之一。使用Python语言管理Docker容器,不仅可以自动化繁琐的容器操作,还能…...
SQL基础入门——SQL基础语法
1. 数据库、表、列的创建与管理 在SQL中,数据库是一个数据的集合,包含了多个表、视图、索引、存储过程等对象。每个表由若干列(字段)组成,表中的数据行代表记录。管理数据库和表的结构是SQL的基础操作。 1.1 创建数据…...
Lumos学习王佩丰Excel第十八讲:LOOKUP函数与数组
一、回顾统计函数 1、使用SUMIF函数 sumif(条件区域,求和条件,求和区域) 2、使用SUMIFS函数 SUMIFS(求和范围, 条件范围1, 条件1, 条件范围2, 条件2, ...) 二、认识数组 1、数组生成原理 所谓数组,是有序的元素序列。组成数组的各个变量称为数组的元素。对于Ex…...