go基础+面试题(持续更新中...)

2023-11-13

go基础+面试题

Go基础

main

golang表达式中,语句末加“;“和不加都可,建议不加。
函数的 { 一定和函数名在同一行,不然编译报错。

Main注意点
main函数不能带参数
main函数不能定义返回值
main函数所在的包必须为main包
main函数中可以使用flag包来获取和解析命令行参数

简要描述go中的main和init函数的区别
首先,这两个函数应用位置不同,init函数可以应用于所有的package,main只能应用于 package main,需要注意的是虽然一个package中可以写任意多个init,但是无论是从可读性还是可维护性来说,都是不推荐的; 其次,这两个函数定义时都不能有任何的参数和返回值, 最后,个人理解,init函数为初始化操作,main函数为程序入口。

变量

变量的声明

局部变量

//方法一:声明一个变量 默认值是0

var a int 

//方法二:声明一个变量 初始化一个值

var b int = 100

//方法三:在初始化的时候,可以省去数据类型,通过自动匹配当前变量的数据类型

var c = 100

//方法四:(常用)省去var 关键字,直接自动匹配

e := 100 

全局变量

同上,方法四不支持全局变量
多变量声明
单行写法

var xx,yy = 100,"hej"

多行写法

var (
  ww int = 100
  jj = true
)

go语法糖 := for range
可变参数规则
可变参数必须要位于函数列表尾部
可变参数是被当作切片来处理的
函数调用时
可变参数可以不填
函数调用时
可变参数可以填入切片

常量与iota

常量

const a int = 10
const(
  a = 10
  b = 20
)

–//iota 与const来表示枚举类型

const (
	//可以在const()添加一个iota,每行的iota都会累加1,第一行默认为0
  BEIGIN = 10*iota   //iota = 0
  SHNGHAI			 //iota = 1
  SHENHEN 			 //iota = 2
  )

string和[]byte如何取舍

两者因数据结构不同,其衍生出来的方法也不同,要跟据实际应用场景来选择
string 擅长的场景
需要字符串比较的场景
不需要nil字符串的场景
[]byte擅长的场景
修改字符串的场景,尤其是修改粒度为1个字节;
函数返回值,需要用nil表示含义的场景;
需要切片操作的场景;
虽然string适用的场景不如[]byte多
但因为string直观,在实际应用中还是大量存在
在偏底层的实现中 []byte使用更多

string与nil类型的问题

nil空值的赋值
空值, 空指针,所有Golang中的引⽤类型都可以⽤nil进⾏赋值 引⽤类型: interface , function, pointer, map, slice, channel.
string: 如果表示⼀个string的空值, ⽤空字符串来表示 “”
不能够将nil赋值给⼀个string类型

Iota编译原理

const块中每一行在GO中使用spec数据结构描述,spec声明如下:

ValueSpec.Names:这个切片中保存了一行中定义的常量
如果一行定义N个常量,那么 ValueSpec.Names切片长度即为N
const块实际上是spec类型的切片,用于表示const中的多行
所以编译期间构造常量时的伪算法如下:

可以更清晰的看出iota实际上是遍历const块的索引
每行中即便多次使用iota,其值也不会递增

内存四区

数据类型的本质 固定内存⼤⼩的别名
数据类型的作⽤ 编译器预算对象或变量分配内存空间的⼤⼩
内存四区:
(1)栈区
空间较⼩,要求数据读写性能⾼,数据存放时间较短暂。由编译器⾃动分配和释 放,存放函数的参数值、函数的调⽤流程⽅法地址、局部变量等(局部变量如果 产⽣逃逸现象,可能会挂在在堆区)
(2)堆区
空间充裕,数据存放时间较久。⼀般由开发者分配及释放(但是Golang中会根据 变量的逃逸现象来选择是否分配到栈上或堆上),启动Golang的GC由GC清除机 制⾃动回收。
(3)全局区
静态全局变量区 全局变量的开辟是在程序在main之前就已经放在内存中。⽽且对 外完全可⻅。即作⽤域在全部代码中,任何同包代码均可随时使 ⽤,在变量会搞混淆,⽽且在局部函数中如果同名称变量使⽤:=赋 值会出现编译错误。
常量区 常量区也归属于全局区,常量为存放数值字⾯值单位,即不 可修改。或者说的有的常量是直接挂钩字⾯值的。 const cl = 10 cl是字⾯量10的对等符号。
(4)代码区

存放代码逻辑的内存

struct结构体

struct结构体是否能比较
比较规则一:只有相同的类型的结构体才可以⽐较(1 结构体的属性类型, 2 属性的顺序)
比较规则二: 即使两个结构体的属性类型和顺序相同,但是里面存在不可比较类型,依然是不可以直接==⽐较的。 ⽐如 map,slice 可以参考⽤reflect.DeepEqual方法来进行比较

函数

返回多个返回值
func fool(a string,b int)(r1 int,r2 int){
//第一个()表示形参入参,如果多个传参一样,可以合起来写(a,b string),第二个()表示函数的返回值有名称的,无名称的表示(int,int)
}

make与new的区别

new 的作用是初始化一个指向类型的指针(*T)
make 的作用是为 slice,map 或 chan 初始化并返回引用(T)。

new函数是内建函数,函数定义:func new(Type) *Type
使用new用于使用type声明的类型的内存分配。传递给new 函数的是一个类型,不是一个值。返回值是 指向这个新分配的零值的指针。

单例实现

var once sync.Once
 
type manager struct {name string}
var single *manager
 
func Singleton() *manager{
	once.Do(func() {
		single = &manager{"a"}
	})
	return single
}

go语言中的for循环?

for循环支持continue和break来控制循环,但是它提供了一个更高级的break,可以选择中断哪一个循环
for循环不支持以逗号为间隔的多个赋值语句,必须使用平行赋值的方式来初始化多个变量

go语言中的switch语句?

单个case中,可以出现多个结果选项
只有在case中明确添加fallthrough关键字,才会继续执行紧跟的下一个case

go语言中没有隐藏的this指针,这句话是什么意思?

方法施加的对象显式传递,没有被隐藏起来
golang的面向对象表达更直观,对于面向过程只是换了一种语法形式来表达
方法施加的对象不需要非得是指针,也不用非得叫this

go语言中的引用类型包含哪些?

数组切片、字典(map)、通道(channel)、接口(interface)

go语言中指针运算有哪些?

可以通过“&”取指针的地址
可以通过“*”取指针指向的数据

import 导包

import _ “fmt” 给fmt包起一个别名,匿名,无法使用当前包的方法,但是会执行当前包内部的init()方法。
import aa “fmt” 给fmt包起一个别名aa,aa.Println()来直接调用。
import .“fmt” 将当前fmt包中的全部方法,导入到当前本包的作用域中,fmt包中的全部方法可以直接使用api来调用,不需要fmt.api来调用,(不建议使用,可能会有重名的包)

指针

defer

Defer作用

用于延迟函数的调用
每次defer都会把一个函数压入栈中
函数返回前再把延迟的函数取出并执行
我们把创建defer的函数称为主函数
defer语句后面的函数称为延迟函数
延迟函数可能有输入参数
参数可能来源于定义defer的函数
延迟函数也可能引用主函数用于返回的变量
也就是说延迟函数可能会影响主函数的一些行为
延迟函数fmt.Println(aInt)的参数在defer语句出现时就已经确定了(这句话是关键)

defer的执行顺序

栈 先进后出
defer和return谁先谁后:return之后的语句先执行,defer后的语句后执行

defer规则

规则一:延迟函数的参数在defer语句出现时就已经确定下来了
规则二:延迟函数执行按后进先出顺序执行,即先出现的 defer最后执行
规则三:延迟函数可能操作主函数的具名返回值
函数返回过程
关键字return不是一个原子操作
实际上return只代理汇编指令ret,即将跳转程序执行
比如语句 return i
实际上分两步进行
将i值存入栈中作为返回值
然后执行跳转
而defer的执行时机正是跳转前
所以defer执行时还是有机会操作返回值的

defer 实现原理

在这里插入图片描述

defer后面一定要接一个函数,所以defer的数据结构跟一般函数类似
也有栈地址、程序计数器、函数地址等等。
与函数不同的一点
它含有一个指针,可用于指向另一个defer
每个goroutine数据结构中实际上也有一个defer 指针
该指针指向一个defer的单链表
每次声明一个defer时,就将defer插入到单链表表头
每次执行defer时,就从单链表表头取出一个defer执行
一个goroutine可能连续调用多个函数
defer添加过程跟上述流程一致
进入函数时添加defer
离开函数时取出 defer
所以即便调用多个函数,也总是能保证defer是按FIFO方式执行的

defer的创建和执行

源码包 src/runtime/panic.go 定义了两个方法分别用于创建和执行defer
deferproc(): 在声明defer处调用,其将defer函数存入goroutine的链表中
deferreturn():在return指令,准确的讲是在ret指令前调用
其将defer从goroutine链表中取出并执行
可以简单这么理解,在编译在阶段
声明defer处插入了函数deferproc()
在函数return前插入了函数 deferreturn()。

defer总结

defer定义的延迟函数参数在defer语句出时就已经确定
defer定义顺序与实际执行顺序相反
return不是原子操作
执行过程是: 保存返回值(若有)—>执行defer(若有)—>执行ret跳转
申请资源后立即使用defer关闭资源是好习惯

数组和动态数组 切片slice

数组

声明数组的方式

var myArray1 [10]int
myArray2 := [10] int{1,2,3,4}
myArray3 := [4] int{1,2,3,4}  

数组的长度是固定的,固定长度的数组在传参时候,要严格匹配数组的类型的。

func printArray(myArray [4]int){
  //值拷贝
}

动态数组 切片slice

myArray := [] int{1,2,3,4}
func printArray(myArray []int){
  //引用传递   而 且不同元素长度的动态数组他们的形参一致。
}

声明方式

//声明slice1是一个切片,并且初始化,默认值是1,2,3,长度len=3
slice1 := []int{1,2,3}
//声明slice1是一个切片,但是没有给slice分配空间
var slice1 []int
slice1 = make([]int, 3)  //开辟3个空间,默认值是0
//声明slice1是一个切片,同时给slice分配3个空间,初始化是0
var slice1 []int = make([]int ,3) 
//声明slice1是一个切片,同时给slice分配3个空间,初始化是0,通过:=推导出slice是一个切片
slice1 := make([]int, 3)

在这里插入图片描述

自动扩容

切片长度与容量不同,长度表示左指针到右指针的距离,容量表示左指针到底层数组末尾的距离
切片扩容机制,qppend的时候,如果长度增加后超过容量,则容量增加2倍
切片的本身变量名即指向当前数组首地址的指针
var numbers = make([]int,3,5)
此时len长度为3,cap容量为5,值为slice = [0,0,0]
numbers = append(numbers,1)
numbers = append(numbers,2)
numbers = append(numbers,3)
向一个容量已满的数组中继续添加元素,会自动扩容增加一个cap容量长度的空间
此时len为6,cap为10
如果不指定cap,那么cap默认为len
var numbers = make([]int,3)
此时len长度为3,cap容量为3,
切片截取

s := []int{1,2,3}
s1 := s[0,2] //[0,2)
=>s1 = [1,2]
//s和s1都指向同一空间,改变任意一个值,s和s1里面的值都改变
s2 :=make([]int ,3)
copy(s2,s)

如果想要分开指向,可使用copy函数深拷贝

扩容
如果原Slice容量小于1024,则新Slice容量将扩大为原来的2倍
如果原Slice容量大于等于1024,则新Slice容量将扩大为原来的1.25倍;
Copy
使用copy()内置函数拷贝两个切片时:
会将源切片的数据逐个拷贝到目的切片指向的数组中
拷贝数量取两个切片长度的最小值
例如
长度为10的切片拷贝到长度为5的切片时
将会拷贝5个元素
也就是说,copy过程中不会发生扩容。
特殊切片
跟据数组或切片生成新的切片一般使用 slice := array[start:end] 方式
这种新生成的切片并没有指定切片的容量,
实际上新切片的容量是从start开始直至array的结束
编程Tips
创建切片时可跟据实际需要预分配容量,尽量避免追加过程中扩容操作,有利于提升性能
切片拷贝时需要判断实际拷贝的元素个数
谨慎使用多个切片操作同一个数组,以防读写冲突

数组与切片的区别?

数组
 数组是具有固定长度且拥有零个或者多个相同数据类型元素的序列
 数组需要指定大小,不指定也会根据初始化的自动推算出大小,不可改变 ;
 数组是值传递;
 数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值。在初始化后长度是固定的,无法修改其长度。当作为方法的参数传入时将复制一份数组而不是引用同一指针。数组的长度也是其类型的一部分,通过内置函数len(array)获取其长度。
切片
 切片表示一个拥有相同类型元素的可变长度的序列。 切片是一种轻量级的数据结构, 它有三个属性:指针、长度和容量。
 切片不需要指定大小;
 切片是地址传递;
 切片可以通过数组来初始化,也可以通过内置函数make()初始化 .初始化时len=cap,在追加元素时如果容量cap不足时将按len的2倍扩容;

nil切片和空切片指向的地址一样吗
nil切片和空切片指向的地址不一样。nil空切片引用数组指针地址为0(无指向任何实际地址)
空切片的引用数组指针地址是有的,且固定为一个值

切片是在栈上分配内存的还是在堆?

这个与:
1.切片的容量有关。
当切片的容量非常小的时候,直接在栈上分配内存,如果非常大则会直接在堆上分配内存,这点与数组是类似的。

2.切片指针的变量是否发生了逃逸
我们可以使用go build --gcflags来观察变量内存的分配过程:

1)如果变量明确被函数外部所引用,那么肯定会在堆上分配内存
2)如果编译期编译器不能确定是否被外部引用,也会直接分配在堆上.
3)但是如果切片在方法中初始化之后,只用于取其中一部分的值返回,仍然不会发生逃逸。

map

声明方式

第一种

//声明myMap是一种map类型,key是string,value是string
var myMap map[string]string
if myMap == nil{
	fmt.Println("myMap是一个空map")
}
//在使用map前,需要使用make给map分配数据空间
myMap = make(map[string]string, 10)
//添加
myMap["one"] = "java"
myMap["two"] = "C++"
myMap["three"] = "Python"

第二种

myMap := make(map[int]string)
myMap[1] = "java"
myMap[2] = "C++"
myMap[3] = "Python"
第三种
myMap := map[string]string{
	"one": "php",
	"two": "c",
	"three": "python",
}

使用方式

//遍历
for key,value := range myMap{
0	
}
//删除
delete(myMap,"one")
//修改
myMap["one"] = "DC0"

map传参是引用传递,
func printMap(myMap map[string]string){

}

底层原理

Golang中map的底层实现是一个散列表
因此实现map的过程实际上就是实现散表的过程
在这个散列表中
主要出现的结构体有两个
一个叫hmap(a header for a go map)
一个叫bucket
hmap
在这里插入图片描述
Buckets
在这里插入图片描述

每个bucket可以存储8个键值对
tophash是个长度为8的数组,**哈希值相同的键(准确的说是哈希值低位相同的键)**存入当前bucket时会将哈希值的高位存储在该数组中,以方便后续匹配
data区存放的是key-value数据,存放顺序是key/key/key/…value/value/value,如此存放是为了节省字节对齐带来的空间浪费
overflow 指针指向的是下一个bucket,据此将所有冲突的键连接起来
注意:上述中data和overflow并不是在结构体中显示定义的,而是直接通过指针运算进行访问的
下图展示bucket存放8个key-value对:
在这里插入图片描述
Hmap and buckets
在这里插入图片描述

Golang的map中也有这么一个哈希函数
也会算出唯一的值
对于这个值的使用,Golang把求得的值按照用途一分为二:
高位和低位
在这里插入图片描述

如图所示
蓝色为高位
红色为低位
然后
低位用于寻找当前key属于hmap中的哪个bucket
而高位用于寻找bucket中的哪个key
bucket中有个属性字段是“高位哈希值”数组
这里存的就是蓝色的高位值
用来声明当前bucket中有哪些“key”
便于搜索查找
需要特别指出的一点是:
我们map中的key/value值都是存到同一个数组中的
并不是key0/value0/key1/value1的形式
是key/key……value/value形式
这样做的好处是:
在key和value的长度不同的时候
可以消除padding带来的空间浪费。
负载因子
用于衡量一个哈希表冲突情况,公式为:
// 负载因子 = 键数量/bucket数量
// 例如,对于一个bucket数量为4,包含4个键值对的哈希表来说
// 这个哈希表的负载因子为1
哈希表需要将负载因子控制在合适的大小
超过其阀值需要进行rehash,也即键值对重新组织:
哈希因子过小,说明空间利用率低
哈希因子过大,说明冲突严重,存取效率低
每个哈希表的实现对负载因子容忍程度不同
比如Redis实现中负载因子大于1时就会触发rehash
而Go则在在负载 因子达到6.5时才会触发rehash
因为Redis的每个bucket只能存1个键值对,而Go的bucket可能存8个键值对, 所以Go可以容忍更高的负载因子。

哈希冲突

当有两个或以上数量的键被哈希到了同一个bucket时,我们称这些键发生了冲突
Go使用链地址法来解决键冲突
由于每个bucket可以存放8个键值对,所以同一个bucket存放超过8个键值对时就会再创建一个键值对,用类似链表的方式将bucket连接起来

bucket数据结构指示下一个bucket的指针称为overflow bucket,意为当前bucket盛不下而溢出的部分
哈希冲突并不是好事情,它降低了存取效率
好的哈希算法可以保证哈希值的随机性
但冲突过多也是要控制的

扩容

渐进式扩容

扩容的前提条件
当新元素将要添加进map时,都会检查是否需要扩容
扩容实际上是以空间换时间的手段
触发扩容的二条件:
负载因子 > 6.5时,也即平均每个bucket存储的键值对达到6.5个
overflow数量 > 2^15时,也即overflow数量超过32768时
增量扩容
新建一个bucket,长度是原来的2倍,然后旧bucket数据搬迁到新的bucket。一次性搬迁将会造成比较大的延时,Go采用逐步搬迁策略:即每次访问map时都会触发一次搬迁,每次搬迁2个键值对。
在这里插入图片描述

当前map存储了7个键值对,只有1个bucket。此负载因子为7。再次插入数据时将会触发扩容操作,扩容之后再将 新插入键写入新的bucket
当第8个键值对插入时,将会触发扩容,扩容后示意图如下:
在这里插入图片描述

hmap数据结构中oldbuckets成员指原bucket
buckets指向了新申请的bucket
新的键值对被插入新的 bucket中
后续对map的访问操作会触发迁移,将oldbuckets中的键值对逐步的搬迁过来
当oldbuckets中的键 值对全部搬迁完毕后,删除oldbuckets
搬迁完成后的示意图如下:
在这里插入图片描述

数据搬迁过程中
原bucket中的键值对将存在于新bucket的前面
新插入的键值对将存在于新bucket的后面
实际搬迁过程中比较复杂

等量扩容

所谓等量扩容,实际上并不是扩大容量
buckets数量不变,重新做一遍类似增量扩容的搬迁动作
把松散的键值对重新排列一次,以使bucket的使用率更高,进而保证更快的存取
在极端场景下
比如不断的增删,而键值对正好集中在一小部分的bucket
这样会造成overflow的bucket数量增多,但负载因子又不高
从而无法执行增量搬迁的情况
overflow的buckt中大部分是空的,访问效率会很差。
此时进行一次等量扩容,即buckets数量不变
经过重新组织后
overflow的bucket数量会减少,即节省了空间又会提高访问效率
查找过程
跟据key值算出哈希值
取哈希值低位与hmpa.B取模确定bucket位置
取哈希值高位,在tophash数组中查询
如果tophash[i]中存储值也哈希值相等,则去找到该bucket中的key值进行比较
当前bucket没有找到,则继续从下个overflow的bucket中查找
如果当前处于搬迁过程,则优先从oldbuckets查找
注:如果查找不到,也不会返回空值,而是返回相应类型的0值。
插入过程
新员素插入过程如下:
跟据key值算出哈希值
取哈希值低位与hmap.B取模确定bucket位置
查找该key是否已经存在,如果存在则直接更新值
如果没找到将key,将key插入

并发sync.Map

sync.Map 的实现原理可概括为:
• 通过 read 和 dirty 两个字段将读写分离,读的数据存在只读字段 read 上,将最新写入的数据则存在 dirty 字段上
• 读取时会先查询 read,不存在再查询 dirty,写入时则只写入 dirty
• 读取 read 并不需要加锁,而读或写 dirty 都需要加锁
• 另外有 misses 字段来统计 read 被穿透的次数(被穿透指需要读 dirty 的情况),超过一定次数则将 dirty 数据同步到 read 上
• 对于删除数据则直接通过标记来延迟删除

sync.Map通过内部存储的两个map来实现了优化:分别是键(key) 固定的read表和包含所有键值对的dirty。所有对read上已有的键值对的增删改查操作都是无锁实现,考虑到的是“写特别少几乎固定”的场景,因为基本用不上锁,从而大大提高了性能。
无论是read还是dirty,存储的都是值的地址,而且是共享地址的。也就是说所有对read的无锁增删改查都会同步反馈在dirty上。所以对read增删改查没有经过dirty而dirty却始终反映最新值。

怎么实现并发安全map

  1. map+读写锁RWMutex
  2. sync.Map
  3. 单协程操作map,用channel通信
    由一个协程 操作map ,其他协程 通过 channle 告诉这个协程应该 怎么操作。其实这样子 性能不是很好,因为 channle 底层 也是锁 ,而且 map 存数据 是要 计算hash的 ,之前是 多个协程自己算自己的hash ,现在变成了一个协程计算了。但是这个思路还是可以,不仅仅是 在 map上可以这么操作。socket 通信啊, 全局 唯一对象的调用啊,都可以用此思路

面向对象

封装

//如果类名首字母大写,表示其他包也能访问,
如果类的首字母大写,表示该属性对外是能够访问的,否则只能给当前包的内部访问

//this是调用该方法的对象的一个副本(拷贝)

继承

多态 interface

interfa本质是一个指针 父类指针,子类继承
多态的三要素 1、有interface接⼝,并且有接⼝定义的⽅法。 2、有⼦类去重写interface的接⼝。 3、有⽗类指针指向⼦类的具体对象

interface空接口与类型断言机制

通用万能类型 interface{} 引用任意类型的数据类型

interface{} 和 interface{}
interface{}本身不是万能指针, 就是eface结构体的地址。
如果以
interface{}作为形参,那么他只能够接收
interface{}类型的实参

反射reflect和内置pair

反射概念

反射提供一种让程序检查自身结构的能力
反射是困惑的源泉
反射三定律
反射第一定律:反射可以将interface类型变量转换成反射对象
reflect.Type 提供一组接口处理interface的类型,即(value, type)中的type
reflect.Value 提供一组接口处理interface的值,即(value, type)中的value
反射第二定律:反射可以将反射对象还原成interface对象
在这里插入图片描述

反射第三定律:反射对象可修改,value值必须是可设置的
reflect.Value 提供了 Elem() 方法,可以获得指针指向的 value
在这里插入图片描述

值接收者,指针接收者
如果实现了接收者是值类型的方法,会隐含地也实现了接收者是指针类型的方法,相反不行
类型转换和断言的区别
类型转换、类型断言本质都是把一个类型转换成另外一个类型
不同之处在于
类型断言是对接口变量进行的操作
类型转换
对于类型转换而言,转换前后的两个类型要相互兼容才行
在这里插入图片描述

断言

对接口进行的操作
在这里插入图片描述

这样,即使断言失败也不会 panic
断言其实还有另一种形式
就是利用 switch 语句判断接口的类型
每一个 case 会被顺序地考虑
当命中一个 case 时
就会执行 case 中的语句

结构题标签tag

Go是如何管理tag的

在这里插入图片描述

可见
描述一个结构体成员的结构中包含了 StructTag
而其本身是一个 string 。也就是说 Tag 其实是结构体字段的一个组成部分
Tag存在的意义
使用反射可以动态的给结构体成员赋值
正是因为有tag,在赋值前可以使用tag来决定赋值的动作。
Tag常见用法
JSON数据解析
ORM映射
在json中的应用
结构体转化为json
在这里插入图片描述

select

特性

select语句中除default外,每个case操作一个channel,要么读要么写
select语句中除default外,各case执行顺序是随机的
select语句中如果没有default语句,则会阻塞等待任一case
select语句中读操作要判断是否成功读取,关闭的channel也可以读取

select机制用来处理异步IO问题
select机制最大的一条限制就是每个case语句里必须是一个IO操作
golang在语言级别支持select关键字
select关键字的用法与switch语句非常类似,后面要带判断条件

select可以用于什么

  1. goroutine超时设置,防止goroutine一直执行导致内存不释放等问题。
  2. 判断channel是否已满或空。如实现一个池线程,当channel已被写满,暂无空闲worker在进行读取,进入default,返回一个暂无可分配资源错误。
    select的case的表达式必须是一个channel类型,所有case都会被求值,求值顺序自上而下,从左至右。如果多个case可以完成,则会随机执行一个case,如果有default分支,则执行default分支语句。如果连default都没有,则select语句会一直阻塞,直到至少有一个IO操作可以进行。
    break关键字可跳出select的执行。

goroutine && channel

goroutine

goroutine就是一段代码,一个函数入口,以及在堆上为其分配的一个堆栈。所以它非常廉价
协程
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快

chan

channel是Golang在语言层面提供的goroutine间的通信方式
主要用于进程内各goroutine间通信
跨进程通信,建议使用分布式系统的方法来解决

数据结构

在这里插入图片描述

环形队列
作为缓冲区
长度是创建chan时指定的
等待队列
当前goroutine被阻塞的两种情况
1从channel读数据
缓冲区为空
没有缓冲区
2向channel写数据
缓冲区已满
没有缓冲区

被阻塞的goroutine将会挂在channel的等待队列中:
因读阻塞的goroutine会被向channel写入数据的goroutine唤醒;
因写阻塞的goroutine会被从channel读数据的goroutine唤醒;
类型信息
一个channel只能传递一种类型的值
类型信息存储在hchan数据结构中
elemtype代表类型,用于数据传递过程中的赋值
elemsize代表类型大小,用于在buf中定位元素位置

一个channel同时仅允许被一个goroutine读写

channel读写

创建channel
创建channel的过程实际上是初始化hchan结构

类型信息和缓冲区长度由make语句传入
buf的大小则与元素大小和缓冲区长度共同决定
向channel写数据
在这里插入图片描述

从channel读数据
在这里插入图片描述

关闭channel

会把recvq中的G全部唤醒,本该写入G的数据位置为nil
把sendq中的G全部唤醒,但这些G会 panic
panic出现的常见场景还有:
关闭已经被关闭的channel
向已经关闭的channel写数据
关闭值为nil的channel

常见用法

单向channel
单向channel只能用于发送或接收数据
实际上也没有单向channel
channel可以通过参数传递
单向channel只是对channel的一种使用限制
func readChan(chanName <-chan int)
通过形参限定函数内部只能从channel中读取数据
func writeChan(chanName chan<- int)
通过形参限定函数内部只能向channel中写入数据
select
select可以监控多channel
比如监控多个channel,当其中某一个channel有数据时,就从其读出数据
结论
select的case语句读channel不会阻塞,尽管channel中没有数据
这是由于case语句编 译后调用读channel时会明确传入不阻塞的参数
读不到数据时不会将当前goroutine加入到等待队列,而是直接返回
range
range可以持续从channel中读出数据,好像在遍历一个数组一样
channel中没有数据时会阻塞当前goroutine
与读channel时阻塞处理机制一样

无缓冲和有冲突的channel的区别
无缓冲的channel是同步的
有缓冲的channel是非同步的

go语言的同步锁?

(1) 当一个goroutine获得了Mutex后,其他goroutine就只能乖乖的等待,除非该goroutine释放这个Mutex
(2) RWMutex在读锁占用的情况下,会阻止写,但不阻止读
(3) RWMutex在写锁占用情况下,会阻止任何其他goroutine(无论读和写)进来,整个锁相当于由该goroutine独占

go语言的channel特性?

A. 给一个 nil channel 发送数据,造成永远阻塞
B. 从一个 nil channel 接收数据,造成永远阻塞
C. 给一个已经关闭的 channel 发送数据,引起 panic
D. 从一个已经关闭的 channel 接收数据,如果缓冲区中为空,则返回一个零值
E. 无缓冲的channel是同步的,而有缓冲的channel是非同步的

go调度GMP

goroutine是按照抢占式调度的,一个goroutine最多执行10ms就会换作下一个
GMP模型
go的调度原理是基于GMP模型,
G代表一个goroutine,不限制数量;
M=machine,代表一个线程,最大1万,所有G任务还是在M上执行;
P=processor代表一个处理器,每一个允许的M都会绑定一个G,
默认与逻辑CPU数量相等(通过runtime.GOMAXPROCS(runtime.NumCPU())设置)。
P的个数就是GOMAXPROCS(最大256),
M的个数和P的个数不一定一样多(会有休眠的M或者不需要太多的M)(最大10000);每一个P保存着本地G任务队列,也有一个全局G任务队列;
执行顺序

  1. 创建一个G对象,加入到本地队列或者全局队列
  2. 如果还有空闲的P,则创建一个M
  3. M会启动一个底层线程,循环执行能找到的G任务
  4. G任务的执行顺序是,先从本地队列找,本地没有则从全局队列找(一次性转移(全局G个数/P个数)个,再去其它P中找(一次性转移一半)
    启动的时候,会专门创建一个线程sysmon,用来监控和管理,在内部是一个循环:

context包的用途

https://www.jianshu.com/p/6def5063c1eb
用途
是在于控制goroutine的生命周期
goroutine管理、信息传递。context的意思是上下文,在线程、协程中都有这个概念,它指的是程序单元的一个运行状态、现场、快照,包含。context在多个goroutine中是并发安全的。

应用场景

当一个计算任务被goroutine承接了之后,由于某种原因(超时,或者强制退出)我们希望中止这个goroutine的计算任务,那么就用得到这个Context了。
Context的四种结构CancelContext,TimeoutContext,DeadLineContext,ValueContext
context包的cancel调用是幂等的。可以放心多次调用。
场景一:rpc调用
在这里插入图片描述

在主goroutine上有4个RPC,RPC2/3/4是并行请求的,我们这里希望在RPC2请求失败之后,直接返回错误,并且让RPC3/4停止继续计算。这个时候,就使用的到Context。
ctx.Done()结束
场景二:PipeLine
pipeline模式就是流水线模型,流水线上的几个工人,有n个产品,一个一个产品进行组装。

场景三:超时请求
我们发送RPC请求的时候,往往希望对这个请求进行一个超时的限制。当一个RPC请求超过10s的请求,自动断开。当然我们使用CancelContext,也能实现这个功能(开启一个新的goroutine,这个goroutine拿着cancel函数,当时间到了,就调用cancel函数)
context包也实现了这个需求:timerCtx。具体实例化的方法是 WithDeadline 和 WithTimeout。

场景四:HTTP服务器的request互相传递数据
context还提供了valueCtx的数据结构。
这个valueCtx最经常使用的场景就是在一个http服务器中,在request中传递一个特定值,比如有一个中间件,做cookie验证,然后把验证后的用户名存放在request中。
官方的request里面是包含了Context的,并且提供了WithContext的方法进行context的替换。
在使用ValueCtx的时候需要注意一点,这里的key不应该设置成为普通的String或者Int类型,为了防止不同的中间件对这个key的覆盖。最好的情况是每个中间件使用一个自定义的key类型,

异常

空指针解析
下标越界
除数为0
调用panic函数

内存模型

Go特性

抛弃了C/C++中的开发者管理内存的方式
实现了主动申请与主动释放管理
增加了逃逸分析和GC
将开发者从内存管理中释放出来
让开发者有更多的精力去关注软件设计
而不是底层的内存问题

代码中使用的内存地址都是虚拟内存地址
而不是实际的物理内存地址
栈和堆只是虚拟内存上2块不同功能的内存区域
栈在高地址
从高地址向低地址增长
堆在低地址
从低地址向高地址增长
栈和堆相比有这么几个好处
栈的内存管理简单,分配比堆上快
栈的内存不需要回收
而堆需要进行回收
无论是主动free,还是被动的垃圾回收
这都需要花费额外的CPU。
栈上的内存有更好的局部性
堆上内存访问就不那么友好了
CPU访问的2块数据可能在不同的页上
CPU访问数据的时间可能就上去了。

当我们说内存管理的时候
主要是指堆内存的管理

释放内存实质是
把使用的内存块从链表中取出来
然后标记为未使用

Go的内存管理

概述
Golang的内存分配器是基于TCMalloc实现的。Golang 的程序在启动之初,会一次性从操作系统那里申请一大块内存(初始堆内存应该是 64M 左右)作为内存池。这块内存空间会放在一个叫 mheap 的 struct 中管理,mheap 负责将这一整块内存切割成不同的区域(spans, bitmap ,areana),并将其中一部分的内存切割成合适的大小,分配给用户使用。

垃圾回收、三色标记原理
垃圾回收就是对程序中不再使用的内存资源进行自动回收的操作。
1.1 常见的垃圾回收算法:
• 引用计数:每个对象维护一个引用计数,当被引用对象被创建或被赋值给其他对象时引用计数自动加 +1;如果这个对象被销毁,则计数 -1 ,当计数为 0 时,回收该对象。
o 优点:对象可以很快被回收,不会出现内存耗尽或到达阀值才回收。
o 缺点:不能很好的处理循环引用
• 标记-清除:从根变量开始遍历所有引用的对象,引用的对象标记“被引用”,没有被标记的则进行回收。
o 优点:解决了引用计数的缺点。
o 缺点:需要 STW(stop the world),暂时停止程序运行。
• 分代收集:按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,短的放入新生代,不同代有不同的回收算法和回收频率。
o 优点:回收性能好
o 缺点:算法复杂
1.2 三色标记法
• 初始状态下所有对象都是白色的。
• 从根节点开始遍历所有对象,把遍历到的对象变成灰色对象
• 遍历灰色对象,将灰色对象引用的对象也变成灰色对象,然后将遍历过的灰色对象变成黑色对象。
• 循环步骤3,直到灰色对象全部变黑色。
• 通过写屏障(write-barrier)检测对象有变化,重复以上操作
• 收集所有白色对象(垃圾)。
1.3 STW(Stop The World)
• 为了避免在 GC 的过程中,对象之间的引用关系发生新的变更,使得GC的结果发生错误(如GC过程中新增了一个引用,但是由于未扫描到该引用导致将被引用的对象清除了),停止所有正在运行的协程。
• STW对性能有一些影响,Golang目前已经可以做到1ms以下的STW。
1.4 写屏障(Write Barrier)
• 为了避免GC的过程中新修改的引用关系到GC的结果发生错误,我们需要进行STW。但是STW会影响程序的性能,所以我们要通过写屏障技术尽可能地缩短STW的时间。
造成引用对象丢失的条件:
一个黑色的节点A新增了指向白色节点C的引用,并且白色节点C没有除了A之外的其他灰色节点的引用,或者存在但是在GC过程中被删除了。以上两个条件需要同时满足:满足条件1时说明节点A已扫描完毕,A指向C的引用无法再被扫描到;满足条件2时说明白色节点C无其他灰色节点的引用了,即扫描结束后会被忽略 。
写屏障破坏两个条件其一即可
• 破坏条件1:Dijistra写屏障
满足强三色不变性:黑色节点不允许引用白色节点 当黑色节点新增了白色节点的引用时,将对应的白色节点改为灰色
• 破坏条件2:Yuasa写屏障
满足弱三色不变性:黑色节点允许引用白色节点,但是该白色节点有其他灰色节点间接的引用(确保不会被遗漏) 当白色节点被删除了一个引用时,悲观地认为它一定会被一个黑色节点新增引用,所以将它置为灰色

进程、线程、协程之间的区别?
进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元;
同一个进程中可以包括多个线程;
进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束;
线程共享整个进程的资源(寄存器、堆栈、上下文),一个进程至少包括一个线程;
进程的创建调用fork或者vfork,而线程的创建调用pthread_create;
线程中执行时01一般都要进行同步和互斥,因为他们共享同一进程的所有资源;
进程是资源分配的单位
线程是操作系统调度的单位
进程切换需要的资源很最大,效率很低 线程切换需要的资源一般,效率一般 协程切换任务资源很小,效率高 多进程、多线程根据cpu核数不一样可能是并行的 也可能是并发的。协程的本质就是使用当前进程在不同的函数代码中切换执行,可以理解为并行。 协程是一个用户层面的概念,不同协程的模型实现可能是单线程,也可能是多线程。
进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。(全局变量保存在堆中,局部变量及函数保存在栈中)
线程拥有自己独立的栈和共享的堆,共享堆,不共享栈,线程亦由操作系统调度(标准线程是这样的)。
协程和线程一样共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
一个应用程序一般对应一个进程,一个进程一般有一个主线程,还有若干个辅助线程,线程之间是平行运行的,在线程里面可以开启协程,让程序在特定的时间内运行。
协程和线程的区别是:协程避免了无意义的调度,由此可以提高性能,但也因此,程序员必须自己承担调度的责任,同时,协程也失去了标准线程使用多CPU的能力。

新的改变

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;
  3. 增加了 图片拖拽 功能,你可以将本地的图片直接拖拽到编辑区域直接展示;
  4. 全新的 KaTeX数学公式 语法;
  5. 增加了支持甘特图的mermaid语法1 功能;
  6. 增加了 多屏幕编辑 Markdown文章功能;
  7. 增加了 焦点写作模式、预览模式、简洁写作模式、左右区域同步滚轮设置 等功能,功能按钮位于编辑区域与预览区域中间;
  8. 增加了 检查列表 功能。

功能快捷键

撤销:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜体:Ctrl/Command + I
标题:Ctrl/Command + Shift + H
无序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
检查列表:Ctrl/Command + Shift + C
插入代码:Ctrl/Command + Shift + K
插入链接:Ctrl/Command + Shift + L
插入图片:Ctrl/Command + Shift + G
查找:Ctrl/Command + F
替换:Ctrl/Command + G

合理的创建标题,有助于目录的生成

直接输入1次#,并按下space后,将生成1级标题。
输入2次#,并按下space后,将生成2级标题。
以此类推,我们支持6级标题。有助于使用TOC语法后生成一个完美的目录。

如何改变文本的样式

强调文本 强调文本

加粗文本 加粗文本

标记文本

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目 Value
电脑 $1600
手机 $12
导管 $1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列 第二列 第三列
第一列文本居中 第二列文本居右 第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPE ASCII HTML
Single backticks 'Isn't this fun?' ‘Isn’t this fun?’
Quotes "Isn't this fun?" “Isn’t this fun?”
Dashes -- is en-dash, --- is em-dash – is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。2

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图:

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.3.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. mermaid语法说明 ↩︎

  2. 注脚的解释 ↩︎

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

go基础+面试题(持续更新中...) 的相关文章

  • 【计算机毕业设计】白优校园社团网站的设计与实现

    近些年 随着中国经济发展 人民的生活质量逐渐提高 对网络的依赖性越来越高 通过网络处理的事务越来越多 随着白优校园社团网站的常态化 如果依然采用传统的管理方式 将会为工作人员带来庞大的工作量 这将是一个巨大考验 需要投入大量人力开展对社团
  • 【计算机毕业设计】springbootstone音乐播放器的设计与实现

    随着我国经济的高速发展与人们生活水平的日益提高 人们对生活质量的追求也多种多样 尤其在人们生活节奏不断加快的当下 人们更趋向于足不出户解决生活上的问题 stone音乐播放器展现了其蓬勃生命力和广阔的前景 与此同时 为解决用户需求 stone
  • Python自动化测试 | 如何使用Robot Framework进行自动化测试?

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 CSDN博客 文章浏览阅读2 3k次 点赞85次 收藏11次 你知不知道有这么一个软件测试面试的刷题小程序 里面包含了面试常问的软件测试基础题 web自
  • 华为OD机试2024年最新题库(Java)

    我是一名软件开发培训机构老师 我的学生已经有上百人通过了华为OD机试 学生们每次考完试 会把题目拿出来一起交流分享 重要 2024年1月 5月 考的都是OD统一考试 C卷 题库已经整理好了 命中率95 以上 这个专栏使用 Java 解法 问
  • 面试官随便问几个问题就知道你究竟做没做过微信支付宝支付

    面试官随便问几个问题就知道你究竟做没做过微信支付宝支付 你知道直连模式和服务商模式吗 网上的课程一般给你演示的都是直连模式 而企业中有不少是申请成为了服务商 因为里面有佣金提成 我粗俗地解释 直连模式 就是说你是一个会做生意的老板 自己会搞
  • (2024最新整理)Java最全八股文及答案!

    Java的特点 Java是一门面向对象的编程语言 面向对象和面向过程的区别参考下一个问题 Java具有平台独立性和移植性 Java有一句口号 Write once run anywhere 一次编写 到处运行 这也是Java的魅力所在 而实
  • 计算机Java项目|尤文图斯足球俱乐部网上商城系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 计算机Java项目|在线图书管理

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • 2024史上最全Java面试八股文(带全部答案)

    今天要谈的主题是关于求职 求职是在每个技术人员的生涯中都要经历多次 对于我们大部分人而言 在进入自己心仪的公司之前少不了准备工作 有一份全面细致 面试题 将帮助我们减少许多麻烦 在跳槽季来临之前 特地做这个系列的文章 一方面帮助自己巩固下基
  • 面试官:分库分表后如何生成全局ID?

    分库分表后就不能使用自增 ID 来作为表的主键了 因为数据库自增 ID 只适用于单机环境 但如果是分布式环境 是将数据库进行分库 分表或数据库分片等操作时 那么数据库自增 ID 就会生成重复 ID 从而导致业务查询上的问题 所以此时 可以使
  • 【go语言】读取toml文件

    一 简介 TOML 全称为Tom s Obvious Minimal Language 是一种易读的配置文件格式 旨在成为一个极简的数据序列化语言 TOML的设计原则之一是保持简洁性 易读性 同时提供足够的灵活性以满足各种应用场景 TOML
  • MongoDB - 整合 SpringBoot 操作全流程

    目录 一 MongoDB 整合 SpringBoot 1 1 引入依赖 1 2 配置文件 1 3 集合操作 1 4 相关注解 1 5 文档操作 1 5 1 查询 1 5 2 更新 1 5 3 删除 一 MongoDB 整合 SpringBo
  • 【心电图基线估计和去噪方法的群稀疏正则化】带有群稀疏正则化的心电图基线估计和去噪(Matlab实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码及文章
  • 【Linux】文件周边001之系统文件IO

    樊梓慕 个人主页 个人专栏 C语言 数据结构 蓝桥杯试题 LeetCode刷题笔记 实训项目
  • 2024年华为OD机试真题-分割均衡字符串-Python-OD统一考试(C卷)

    题目描述 均衡串定义 字符串只包含两种字符 且两种字符的个数相同 给定一个均衡字符串 请给出可分割成新的均衡子串的最大个数 约定字符串中只包含大写的 X 和 Y 两种字符 输入描述 均衡串 XXYYXY 字符串的长度 2 10000 给定的
  • 基于节点电价的电网对电动汽车接纳能力评估模型研究(Matlab代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Matlab代码 数据
  • 在 Python 中实现 List 抽象

    在 Python 中 创建一个包含多个对象的 list 很常见 例如 对于一组具有相同功能的对象 比如播放声音 希望能够使用类似 my list play 的语法来触发 list 中所有对象的 play 方法 另一个例子是 当希望关闭 li
  • 如何应对Android面试官-> 玩转 ViewPager 懒加载

    前言 ViewPager 缓存页面与预加载机制 通常我们 ViewPager 在使用的是一般都是结合 Fragment 一起使用 我们先来搭一个简单的使用界面 最终搭建出来的效果如下 简单的 ViewPager Fragment 的实现 比
  • 计算机Java项目|人体健康信息管理系统

    作者简介 Java领域优质创作者 CSDN博客专家 CSDN内容合伙人 掘金特邀作者 阿里云博客专家 51CTO特邀作者 多年架构师设计经验 腾讯课堂常驻讲师 主要内容 Java项目 Python项目 前端项目 人工智能与大数据 简历模板
  • Spring Boot引起的“堆外内存泄漏”排查及经验总结

    Spring Boot引起的 堆外内存泄漏 排查及经验总结 背景 为了更好地实现对项目的管理 我们将组内一个项目迁移到MDP框架 基于Spring Boot 随后我们就发现系统会频繁报出Swap区域使用量过高的异常 笔者被叫去帮忙查看原因

随机推荐

  • Scratch的克隆体

    克隆体 克隆就是将角色本体完全复制一份 包含该角色当前的所有属性 例如造型 位置 颜色 大小等 控制积木中提供了克隆自己积木 在事件积木中 单独提供了一个当作为克隆体启动时的积木 当某个角色被克隆 则其克隆体会触发该事件 故而 对于那些克隆
  • 第十课,OpenGL光照之贴图

    光照贴图 光照贴图 及使用纹理代替物体颜色 物体的实际颜色由物体材质和光照决定 漫反射贴图 使用一张覆盖物体的图像 让我们能够逐片段索引其独立的颜色值 方式 1 将纹理传入 GLuint texture1 loadTexture conta
  • 在 CentOs7 中安装宝塔面板和 Docker(包括MySQL,Redis)

    在 CentOs7 中安装宝塔面板和Docker 包括MySQL Redis 1 使用 Xshell 连接 CentOs7 2 安装宝塔面板 2 1 安装 Tomcat 同 Java 8 2 1 安装 Docker 2 2 安装 MySQL
  • 「考研算法」

    考研算法 前言 本系列文章涉及的算法内容 针对的是哈尔滨工业大学854科目 在本文中通过具体的算法题进行讲解相应算法 今天涉及的算法主要有线性筛 十大排序中快速排序和归并排序 C语言版 一 线性筛算法 算法题目 筛质数 给定一个正整数 n
  • ctf_show_web4

    这一道题他们给的提示是 url var log nginx access log 用上面的这个来找出日志接下来就是文件包含这里我们要用到bp 抓包后我们在User Agent中插入一句话木马 之后连接你的蚁剑 测试连接连接成功 最后就会得到
  • Android项目如何上传Gitee仓库

    前言 最近Android项目比较多 我都是把Android项目上传到Gitee中去 GitHub的话我用的少 可能我还是更喜欢Gitee吧 毕竟Gitee仓库用起来更加方便 一 创建Gitee仓库 1 先创建一个Gitee账号 然后登录上去
  • 基于区块链智能合约的疫苗溯源系统

    绪论 该系统基于以太坊的Solidity进行智能合约开发 并通过hardhat进行部署在了本机 通过Mocha和Chai进行了单元测试的编写 同时提供了一个基于React的前端界面与用户进行交互 区块链的介绍 不难看出 区块链技术对现有的经
  • JS(ES5,ES6)实现栈数据结构

    栈是一种遵从后进先出原则的有序集合 新添加的或待删除的元素都保存在栈的同一端 称作栈顶 另一端叫做栈底 栈也被用在编程语言的编译器和内存中保存变量 方法调用等 ES5实现 function Stack let items 向栈添加元素 th
  • Git拉取分支代码小结以及问题解决

    更全面的版本 三分钟学会git 一 拉取代码 git clone git example com myproject 默认拉取的master 若需要切换分支 git branch a master origin HEAD origin ma
  • vlc-android源码的编译

    一 编译前须知 1 参考官方文档 https wiki videolan org AndroidCompile 2 必须要在Linux环境下 3 我使用的是ubuntu 二 编译前安装开发工具 1 Linux操作系统 我选择的是在windo
  • 七牛云存储java_api代码实现

    这是思维图 画的有点拉 看官老爷凑合看 接下来就按照这个逻辑来实现 七牛云本身是提供的Java SDK的 可以完成图片上传和删除 我们可以参考官方提供的例子 官方文档 https developer qiniu com kodo sdk 1
  • Python组合数据的输入问题

    以输入5个数据为例 以前是单个变量的处理 所以习惯单个数据输入 a eval input 输入5个数据 自然想到的就是让它循环5次 这种方式执行时 因为每次输入回车 相当于竖着输 能不能一次输入呢 在一行横着输 元组 t eval inpu
  • 网络攻防——Fiddler工具的使用

    Fiddler工具的使用 1 引言 2 什么是Fiddler 3 Fiddler的基本使用 4 基于手机模拟器的APP抓包 5 接口捕获 6 引言 7 鸣谢 1 引言 虽然之前写了退出一切关于编程的学习 其实我还想学react typesc
  • 【cdk的使用】C语言 跨平台生成伪随机数

    Github地址 https github com wujin1989 cdk C标准库中有rand 和srand 函数用来生成伪随机数 但是虽然在标准库里 确依然不能跨平台 因为C标准里没有明确rand 函数生成的随机数范围 比如 win
  • 【Xilinx DMA SG】Xilinx DMA SG 模式

    DMA简介 AXI 直接存储器访问 AXI DMA IP 提供高带宽直接存储器 AXI4 存储器映射和 AXI4 Stream IP 接口之间的访问 它SG模式还可以从中央处理中卸载数据移动任务 基于处理器的系统中的单元 CPU 初始化 状
  • 机器学习入门——线性回归预测广告投入数据集

    0 Advertising数据集 Advertising数据集是关于广告收益与广告在不同的媒体上投放的相关数据 分别是在TV Radio Newspaper三种媒体上投放花费与 投放所产生的收益的数据 数据共有200条 数据的格式如下 1
  • 线性回归最小二乘法和梯度下降法-详细

    原文 https blog csdn net y990041769 article details 69567838 问题描述 首先我们定义问题 线性回归要解决的问题就是根据给出的数据学习出一个线性模型 例如我们最常说的身高和体重的关系 以
  • EasyConnect linux(ubuntu 20.04)下运行报错

    EasyConnect 67186 Pango ERROR 10 01 20 576 Harfbuzz version too old 1 3 1 报错原因 本地系统更新导致相关依赖包的版本高于EasyConnect需要的版本 解决方式 下
  • vue3中采用pinia集中管理数据

    Pinia 起始于 2019 年 11 月左右的一次实验 其目的是设计一个拥有组合式 API 的 Vue 状态管理库 从那时起 我们就倾向于同时支持 Vue 2 和 Vue 3 并且不强制要求开发者使用组合式 API 下载依赖 yarn a
  • go基础+面试题(持续更新中...)

    go基础 面试题 Go基础 main 变量 变量的声明 局部变量 全局变量 常量与iota 常量 string和 byte如何取舍 string与nil类型的问题 Iota编译原理 内存四区 struct结构体 函数 make与new的区别