day 21
进程、线程、协程的区别
进程:操作系统分配资源的最小单位,其中可以包含一个或者多个线程,进程之间是独立的,可以通过进程间通信机制(管道,消息队列,共享内存,信号量,信号,socket套接字)通信,进程的切换涉及到许多资源耗费时间多。
线程:轻量级的进程,一个进程之间可以有多个线程,系统调度的最小单位,多个线程之间共享一部分进程的资源,有线程独立的线程栈,程序计数器,寄存器等。可以通过共享内存通信,相对于进程切换的资源较少,时间短。
协程:用户态的线程,不由系统调度,而是由程序调度(不需要陷入内核),有自己独立的协程栈,寄存器等。协程间通信可以用共享内存或者通道。
Golang 的 GMP 调度
G:协程对象,存放协程的上下文和栈等;
M:执行协程的线程;
P:处理器,存放协程对象的队列,调度协程到M上执行。
说下 GMP 的整个过程
- 新创建一个协程后,放到P的本地队列中,P找一个空闲的M去绑定并执行,如果没有空闲的M就创建一个。
- 绑定后,P调度协程执行,如果协程执行到阻塞事件后,将协程置为阻塞状态,如果是系统调用,文件io或者网络io时,M和G绑定一起阻塞,P与M解绑找空闲的M执行下一个协程。(如果是非系统调用,例如等待锁,就将协程放到阻塞事件的等待队列中,M执行P中的下一个协程),如果没有,就从全局队列中取,全局队列为空就从其余P中偷取1/2协程。
- 系统调用后,M重新获取一个P或等待新的P可用,G阻塞结束后,放到P队列尾部。
C++和go的指针有什么不同?
- C++可以对指针±运算,go中不可。
- C++的内存需要手动管理或者智能指针,go中有垃圾回收机制GC。
- C++的指针可以指向数组,但是go中只能指向数组中的某个元素。
- C++的指针必须要初始化,go中的指针没有初始化是nil,各类型默认值。
go的接口的作用是什么?
用于实现多态,某个类实现了该接口的所有方法就是实现了这个接口,在使用这个接口的方法时,可以使用这个接口的指针,指向传入的实现接口的对象,根据不同的对象,调用这个接口的方法的不同实现。
go当中make和new有什么区别?
new接收类型,分配堆内存返回该类型的指针,将该类型的零值存到内存中。
make用于为切片,通道,map分配内存返回他们的引用,并初始化他们。
new对于切片,通道,map分配后并没有对内存进行初始化,而make进行初始化了,可以直接使用。
go如何对字符串进行拼接?
- 可以使用+来拼接:创建一个新的字符串对象存放拼接后的值。
- string.join可以用于字符切片拼接起来,例如:字符切片strs中的两个字符串,中间用空格拼接。
func main() {strs := []string{"Hello", "World"}result := strings.Join(strs, " ")fmt.Println(result)
}
- strings.Builder:专门构建字符串的结构体,例如:创建一个构建字符串的对象,利用其writestring函数拼接一个字符串,再将其转换为string。
底层使用字节切片,用其保存字符,通过append拼接两个字节切片,切片容量不够可以扩容。
package mainimport ("fmt""strings"
)func main() {var builder strings.Builderbuilder.WriteString("Hello")builder.WriteString(" ")builder.WriteString("World")result := builder.String()fmt.Println(result)
}
go局部变量怎么初始化的?
- 先声明再初始化:例如var a int = 10
- 声明初始化:a := 10
go的常量会不会分配内存地址?
不会分配地址,编译时就已经确定值,编译器将常量值嵌入到程序里。