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

Go语言 相关概念深入分析

1. golang语言中new和make的区别

在 Go 语言中,new 和 make 是用于创建不同类型的值的内置函数。它们有以下区别:
new 函数用于创建指向新分配的零值的指针。
它接受一个类型作为参数,并分配该类型的零值,并返回一个指向该值的指针。
new 函数返回的是指针类型,适用于创建指向结构体、基本类型(如整数、浮点数)等值的指针。
new 函数不会初始化内存,返回的指针指向的值将是该类型的零值。
以下是使用 new 函数的示例:

var p *int
p = new(int)
*p = 42
fmt.Println(*p) // 输出: 42

make 函数:
make 函数用于创建切片、映射和通道等引用类型的值。
它接受一个类型、长度和容量作为参数,并返回一个初始化后的引用类型的值。
make 函数返回的是引用类型的值,适用于创建切片、映射和通道等引用类型。
make 函数会初始化内部数据结构,并返回一个可用的引用类型的值。
以下是使用 make 函数的示例:

var s []int
s = make([]int, 3, 5)
s[0] = 1
s[1] = 2
s[2] = 3
fmt.Println(s) // 输出: [1 2 3]

总结:
new 用于创建指向零值的指针,适用于基本类型和结构体等值的指针。
make 用于创建引用类型(切片、映射、通道)的值,会初始化内部数据结构。

2 在计算机科学中,堆(Heap)和栈(Stack)是两种常见的内存管理方式,它们有以下区别:

内存结构:

栈:栈是一种线性数据结构,具有后进先出(LIFO)的特性。它在程序运行时使用固定的内存块,存储局部变量、函数调用和返回等信息。栈的大小在编译时就确定,并在函数的进入和退出时动态地分配和释放内存。
堆:堆是一种树状结构,用于动态分配和管理内存。堆的大小在程序运行时可以动态地增加或减少,由操作系统分配和管理。堆用于存储动态分配的对象、数据结构等,并且需要手动释放分配的内存。
分配方式:

栈:栈的内存分配是自动的,由编译器或运行时环境自动处理。每当进入一个新的函数时,栈会分配一定大小的内存用于存储局部变量和函数的上下文信息。当函数返回时,栈会自动释放分配的内存。
堆:堆的内存分配是手动控制的,程序员需要显式地请求内存分配,并在不再使用时手动释放内存。通常使用诸如 new、malloc 等函数来分配堆内存,并使用 delete、free 等函数来释放堆内存。
内存管理:

栈:栈的内存管理是自动的,由编译器或运行时环境负责。它的分配和释放过程是快速的,由于栈的内存空间是连续的,因此分配和释放内存只涉及栈指针的移动,效率较高。但栈的空间有限,一般较小。
堆:堆的内存管理是手动的,程序员需要负责分配和释放堆内存。堆的分配和释放过程相对较慢,由于堆是动态分配的,可能存在内存碎片问题。堆的空间较大,可以根据需要动态分配和释放内存。
生命周期:

栈:栈上的变量的生命周期是在其作用域结束时自动销毁,无需手动管理。栈上的局部变量的生命周期与函数的调用关系密切相关。
堆:堆上的对象的生命周期由程序员显式管理,需要手动分配和释放内存。堆上分配的对象可以在其不再被使用时手动释放,否则会造成内存泄漏。

3 uint类型介绍
uint 是 Go 语言中的一种无符号整数类型。它表示非负整数,没有符号位,可以表示正整数和零。

在 Go 语言中,uint 类型的大小取决于底层计算机体系结构的字长,即它的位数。在绝大多数情况下,uint 类型的大小为 32 位或 64 位。

具体而言,以下是 uint 类型及其大小的变体:

uint:根据底层计算机体系结构的字长,可能是 32 位或 64 位。
uint8:8 位无符号整数,取值范围为 0 到 255。
uint16:16 位无符号整数,取值范围为 0 到 65535。
uint32:32 位无符号整数,取值范围为 0 到 4294967295。
uint64:64 位无符号整数,取值范围为 0 到 18446744073709551615。
根据具体的需求,可以选择适当大小的 uint 类型来存储非负整数。例如,如果需要存储一个正整数,但不超过 65535,可以选择使用 uint16 类型,以节省内存空间。

4 go select机制
Go 语言中的 select 语句用于在多个通道上进行非阻塞的选择操作。它类似于其他编程语言中的 switch 语句,但是用于选择可读或可写的通道而不是选择不同的条件。

select 语句的语法如下:

select {
case <-channel1:// 当 channel1 有数据可读时执行的代码
case channel2 <- data:// 当 data 可以写入 channel2 时执行的代码
default:// 当没有任何通道准备好时执行的代码
}

select 语句包含了一系列的 case 子句,每个 case 子句关联一个通道操作。<-channel1 表示从 channel1 读取数据,channel2 <- data 表示将 data 写入 channel2。

当 select 语句执行时,它会检查所有关联的通道,如果其中某个通道已准备好(即可读或可写),对应的 case 子句中的代码会被执行。如果多个通道都准备好,会随机选择其中一个执行。如果没有任何通道准备好,即所有通道都阻塞,那么 default 子句中的代码会被执行。

使用 select 语句可以解决在多个通道上进行并发操作的问题,允许我们在不阻塞的情况下等待多个通道的操作。这是 Go 语言并发编程中非常有用的机制。

rune类型介绍
在Go语言中,rune是一种基本数据类型,用于表示Unicode字符。它实际上是一个32位的整数类型(int32的别名),用于存储Unicode代码点。
由于Unicode字符可以表示不同的语言字符集和符号,而且一些字符可能占用多个字节,因此使用rune类型可以确保正确处理和操作Unicode字符。

中文字符在unicode下占2个字节,在utf-8编码下占3个字节,而golang默认编码正好是utf-8

5 单引号,双引号,反引号的区别?
单引号,表示byte类型或rune类型,对应 uint8和int32类型,默认是 rune 类型。byte用来强调数据是raw data,而不是数字;而rune用来表示Unicode的code point。

双引号,才是字符串,实际上是字符数组。可以用索引号访问某字节,也可以用len()函数来获取字符串所占的字节长度。

反引号,表示字符串字面量,但不支持任何转义序列。字面量 raw literal string 的意思是,你定义时写的啥样,它就啥样,你有换行,它就换行。你写转义字符,它也就展示转义字符。

6 go语言中 map 中删除一个 key,它的内存会释放么?

在 Go 语言中,当你从一个 map 中删除一个 key-value 对时,对应的 key 和 value 不会立即释放内存。相反,它们会等待垃圾回收器(garbage collector)来回收这些内存。

Go 语言的垃圾回收器是自动的,它会周期性地扫描和回收不再被引用的对象。当你删除一个 map 中的 key-value 对时,该 key 和 value 对象仍然存在于内存中,但如果它们没有被其他地方引用,它们将被标记为不可达对象,并在下一次垃圾回收时被回收。

垃圾回收器的工作是基于一些算法和策略的,具体的回收时间取决于多个因素,例如内存压力、对象大小和系统负载等。因此,无法准确预测何时会释放具体的内存。

如果你需要立即释放 map 中删除的 key-value 对所占用的内存,可以通过将对应的 value 设置为 nil 来帮助垃圾回收器更早地回收它们。例如,将其设置为 map[key] = nil。这样,如果没有其他地方引用该 value,它将成为不可达对象,并有望在下一次垃圾回收时被回收。

7 怎么处理对 map 进行并发访问?
方式一、使用内置sync.Map
方式二、使用读写锁实现并发安全map

8 Go 中 init 函数的特征?
答:一个包下可以有多个 init 函数,每个文件也可以有多个 init 函数。多个 init 函数按照它们的文件名顺序逐个初始化。应用初始化时初始化工作的顺序是,从被导入的最深层包开始进行初始化,层层递出最后到 main 包。不管包被导入多少次,包内的 init 函数只会执行一次。应用初始化时初始化工作的顺序是,从被导入的最深层包开始进行初始化,层层递出最后到 main 包。但包级别变量的初始化先于包内 init 函数的执行

9 goroutine 的自旋占用资源如何解决
自旋锁是指当一个线程在获取锁的时候,如果锁已经被其他线程获取,那么该线程将循环等待,然后不断地判断是否能够被成功获取,直到获取到锁才会退出循环。

10. nil map 未初始化,空map是长度为空
可以对未初始化的map进行取值
不能对未初始化的map进行赋值,这样将会抛出一个异常

11. go context介绍
在Go语言中,context是用于跨API边界传递请求范围数据的标准包。context包提供了Context接口和用于创建和操作Context的一些函数。
Context接口定义如下:

type Context interface {Deadline() (deadline time.Time, ok bool)Done() <-chan struct{}Err() errorValue(key interface{}) interface{}
}

Context接口包含以下方法:

Deadline():返回Context的截止时间(如果有的话),以及一个布尔值,指示是否设置了截止时间。
Done():返回一个只读的通道,当Context被取消或超时时,该通道将关闭。
Err():返回与Context关联的错误(如果有的话),通常是由于Context的取消或超时导致的。
Value(key interface{}):根据给定的键返回与Context相关联的值。这个方法用于跨函数传递请求范围的数据。
在实际使用中,我们可以通过context包提供的一些函数来创建和操作Context对象,例如:

context.Background():创建一个空的根Context,在整个应用程序的生命周期内有效。
context.TODO():创建一个空的Context,在无法确定合适的Context时使用。
context.WithCancel(parent Context):创建一个可取消的Context,返回一个新的Context和一个用于取消Context的函数。
context.WithDeadline(parent Context, deadline time.Time):创建一个具有截止时间的Context,返回一个新的Context和一个函数,用于取消Context。
context.WithTimeout(parent Context, timeout time.Duration):创建一个具有超时时间的Context,返回一个新的Context和一个函数,用于取消Context。
context.WithValue(parent Context, key, val interface{}):创建一个带有值的Context,返回一个新的Context,并将键值对存储在其中。
这些函数可以用于创建具有不同属性和特性的Context对象,以便在请求范围内传递数据、控制取消和超时等。

需要注意的是,在Go语言中,Context是并发安全的,可以在多个goroutine之间安全地传递和使用。

12. channel 是否线程安全?锁用在什么地方?
由于channel本身已经提供了线程安全的机制,通常情况下不需要使用额外的锁来保护channel的访问。使用锁的主要场景是在需要对多个共享资源进行原子操作或互斥访问时。

13. 向channel发送数据和从channel读取数据的流程如下:
发送数据到channel:

发送操作使用<-运算符将数据发送到channel。
如果channel是无缓冲的(unbuffered),发送操作会阻塞,直到有接收者从channel中接收数据。
如果channel是有缓冲的(buffered),发送操作会将数据放入缓冲区,直到缓冲区满或有接收者从channel中接收数据。
发送操作完成后,控制权会返回给发送者的goroutine。
从channel读取数据:

接收操作使用<-运算符从channel中读取数据。
如果channel中有可用的数据,接收操作会将数据从channel中取出并返回给接收者。
如果channel是无缓冲的,且没有发送者发送数据,接收操作会阻塞,直到有发送者向channel发送数据。
如果channel是有缓冲的,且缓冲区中有数据,接收操作会立即返回数据。
接收操作完成后,控制权会返回给接收者的goroutine。

14. 进程、线程、协程有什么区别?
进程(Process),线程(Thread)和协程(Coroutine)是计算机多任务处理中的概念,它们之间有以下区别:
进程:

进程是操作系统分配资源的基本单位。它是一个独立的执行实体,具有独立的内存空间和系统资源。
每个进程都有自己的地址空间、文件描述符、打开的文件、进程上下文等。
进程之间相互独立,通过进程间通信(IPC)来实现数据交换。
进程切换开销较大,需要切换上下文,并且进程间的资源隔离较好。
线程:

线程是进程内的执行流,是CPU调度和执行的基本单位。
同一进程内的多个线程共享相同的内存空间和系统资源。
线程之间可以通过共享内存来实现数据共享和通信。
线程切换开销相对较小,因为切换时只需要保存和恢复寄存器状态。
协程:

协程是一种用户态的轻量级线程,也称为非抢占式线程。
协程由用户代码控制,可以显式地进行切换。
同一线程内的多个协程共享相同的栈空间,但拥有独立的寄存器和局部变量。
协程之间的切换开销非常小,因为切换时无需内核介入。
协程通常用于高并发、高性能的任务处理,能够充分利用 CPU。

15. GMP

GMP代表"Go M-Principle",它是Go语言运行时(runtime)中的一个核心概念。GMP实际上是一个缩写,分别代表以下三个重要的组件:

G(Goroutine):Goroutine是Go语言中的轻量级线程,用于实现并发执行。每个Goroutine都有自己的堆栈和上下文,并由Go运行时系统进行调度和管理。

M(Machine):Machine代表操作系统线程(Operating System Thread),也称为"系统线程"。M负责将Goroutine映射到操作系统线程上,并负责调度Goroutine的执行。Go运行时系统会自动创建和管理多个M,以充分利用多核处理器的并行性。

P(Processor):Processor代表逻辑处理器,它是Go运行时系统中的抽象概念。每个P维护了一组Goroutine队列,并负责将Goroutine绑定到M上进行执行。P负责调度M执行Goroutine,当一个Goroutine被阻塞或发生系统调用时,P会从Goroutine队列中选择另一个可执行的Goroutine来运行。

GMP模型的核心思想是将高层的Goroutine与底层的操作系统线程(M)分离开来,并通过逻辑处理器(P)进行调度和管理。这种模型使得Go语言可以高效地实现大规模并发和并行,通过动态地在多个操作系统线程之间调度Goroutine的执行,充分利用了系统资源。

参考:
https://www.zhihu.com/tardis/bd/art/519979757?source_id=1001

相关文章:

  • 2-高可用-负载均衡、反向代理
  • 系列十一(面试)、如何查看JVM的参数?
  • pycharm git 版本回退
  • 先进制造身份治理现状洞察:从手动运维迈向自动化身份治理时代
  • 智能优化算法应用:基于卷尾猴算法3D无线传感器网络(WSN)覆盖优化 - 附代码
  • NPM介绍与使用
  • 导入conda虚拟环境的lib
  • 166. 数独(DFS之剪枝与优化:位运算优化,优化搜索顺序,.可行性剪枝)
  • GLTF/GLB模型在线预览、编辑、动画查看以及材质修改
  • 4.3 C++对象模型和this指针
  • Linux: 常见工具、命令使用集锦
  • C语言—每日选择题—Day54
  • 机器视觉兄弟们,出身寒微,不是耻辱,能屈能伸,方为丈夫
  • 分布式编译distcc
  • 虚拟机多开怎么设置不同IP?虚拟机设置独立IP的技巧
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • AngularJS指令开发(1)——参数详解
  • CSS 提示工具(Tooltip)
  • HTTP那些事
  • jquery ajax学习笔记
  • Netty源码解析1-Buffer
  • Vim Clutch | 面向脚踏板编程……
  • 安卓应用性能调试和优化经验分享
  • 每天一个设计模式之命令模式
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 小程序测试方案初探
  • 一个普通的 5 年iOS开发者的自我总结,以及5年开发经历和感想!
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ###C语言程序设计-----C语言学习(3)#
  • #stm32整理(一)flash读写
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (一)基于IDEA的JAVA基础1
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • .gitignore文件_Git:.gitignore
  • .NET Core WebAPI中封装Swagger配置
  • .Net Web项目创建比较不错的参考文章
  • .NET/C# 使用 ConditionalWeakTable 附加字段(CLR 版本的附加属性,也可用用来当作弱引用字典 WeakDictionary)
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • ::前边啥也没有
  • @Bean有哪些属性
  • @Import注解详解
  • @LoadBalanced 和 @RefreshScope 同时使用,负载均衡失效分析
  • @NoArgsConstructor和@AllArgsConstructor,@Builder
  • [ C++ ] STL_vector -- 迭代器失效问题
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛
  • [2013AAA]On a fractional nonlinear hyperbolic equation arising from relative theory
  • [20150629]简单的加密连接.txt
  • [ACTF2020 新生赛]Include
  • [AIGC] Java 和 Kotlin 的区别
  • [bzoj 3534][Sdoi2014] 重建