Go面试题目

一 

init和main的对比
相同点:
两个函数在定义时不能有任何的参数和返回值 Go程序自动调用
不同点:
init可以应用于任意包中,且可以重复定义多个。
main函数只能用于main包中,且只能定义一个。
make 被用来分配引用类型的内存,返回的还是这三个引用类型本身,make常用。
new 被用来分配除了引用类型的所有其他类型的内存,返回的是指向类型的指针。new不常用。
闭包的特点:
让外部访问函数内部变量成为可能;
局部变量会常驻在内存中;
可以避免使用全局变量,防止全局变量污染;
有一块内存空间被长期占用,而不被释放,会造成内存泄漏
接口:泛型 多态 隐藏具体实现
反射:运行时动态的获取变量类型信息和值信息的机制
GC原理
1首先创建三个集合:白、灰、黑。
2新创建的对象放入白色集合中。
3然后从根节点开始遍历所有对象,把遍历到的对象从白色集合放入灰
4之后遍历灰色集合,将灰色对象_引用的对象_从白色集合放入灰色集合,
5之后将此灰色对象放入黑色集合
6之后遍历灰色集合,将黑色对象_引用的对象_从灰色集合放入黑色集合,
7通过write-barrier(写屏障)检测对象有变化,直到灰色对象中没有对象
8收集所有白色对象垃圾
9一次垃圾回收完成后,将黑色集合变色成白色集合,会进一步gc操作,依此循环


GC优化
1.减少对象
2.少用+
3.避免string和[]byte转化  可以用 strings.Join代替


gc触发条件
1.超过内存大小阈值
2.达到定时时间

内存管理算法TCMalloc

并发模型CSP

调度模型GPM
G: 表示Goroutine,G并非执行体,每个G需要绑定到P才能被调度执行。
P: Processor,   表示逻辑处理器, G和M的调度对象
G只有绑定到P(在P的local runq中)才能被调度,P给M分配任务
M: Machine,对内核级线程的封装,数量对应真实的CPU数(真正干活的对象)
elk的match是拆分匹配
term是精确匹配

 channel线程安全吗

是安全的

HashMap 线程安全原因

不安全 

1.同时添加相同的元素可能会发生碰撞覆盖2.同时对数组进行扩容会有数据丢失

HashMap 不安全解决

Hashtable
ConcurrentHashMap
Synchronized Map

slice与arr区别 

● 切片是指针类型,数组是值类型

● 数组的长度是固定的,而切片不是(切片是动态的数组)

● 切片比数组多一个属性:容量(cap)

● 切片的底层是数组

读写锁或者互斥锁读的时候能写

Go中读写锁包括读锁和写锁,
多个读线程可以同时访问共享数据;
写线程必须等待所有读线程都释放锁以后,才能取得锁;
同样的,读线程必须等待写线程释放锁后,才能取得锁,也就是说读写锁要确保的是如下互斥关系,
可以
同时读,
读-写,写-写都是互斥的。

Channel是同步的还是异步的.

Channel是异步进行的。
channel存在3种状态:

nil,未初始化的状态,只进行了声明,或者手动赋值为nil
active,正常的channel,可读或者可写
close,已关闭,千万不要误认为关闭channel后,channel的值是nil

实现消息队列(多生产者,多消费者)

package main

import (
	"fmt"
	"time"
)

func producer(pname string, ch chan int) {
	for i := 0; i < 4; i++ {
		fmt.Println("producer--", pname, ":", i)
		ch <- i
	}
}

func consumer(cname string, ch chan int) {
	//可以循环 for i := range ch 来不断从 channel 接收值,直到它被关闭。
	for i := range ch {
		fmt.Println("consumer-----------", cname, ":", i)
	}
}

func main() {
	//用channel来传递"产品", 不再需要自己去加锁维护一个全局的阻塞队列
	ch := make(chan int)
	go producer("生产者1", ch)
	go consumer("消费者1", ch)
	time.Sleep(10 * time.Second)
	close(ch)
}

 孤儿进程,僵尸进程

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被
init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的
状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

tcp与udp区别

tcp传输的是数据流,而udp是数据包,tcp会进过三次握手,udp不需要 

TCP三次握手四次挥手

https://blog.csdn.net/fujian9544/article/details/100045552

 网址题目

Golang面试题解析_GoRustNeverStop的博客-CSDN博客

做的答案

1.defer后入先出  panic在defer之后进行执行 

原因出现panic恐慌时候,会先按照defer的后入先出的顺序执行,最后才会执行panic。

2.结构体中套入一个结构体就实现了继承

3.地址与变量

第一个:go func中i是外部for的一个变量,地址不变化,遍历完成后,最终i=10, 故go func执行时,i的值始终是10。过程中的i对应的地址与协程中的地址不是一个,所以不对应。

第二个:go func中i是函数参数,与外部for中的i完全是两个变量。 尾部(i)将发生值拷贝,每次拷贝一个新值,使用过程中的量

func main() {
    runtime.GOMAXPROCS(1)
    wg := sync.WaitGroup{}
    wg.Add(20)
    for i := 0; i < 10; i++ {
        go func() {
            fmt.Println("A: ", i)
            wg.Done()
        }()
    }
    for i := 0; i < 10; i++ {
        go func(i int) {
            fmt.Println("B: ", i)
            wg.Done()
        }(i)
    }
    wg.Wait()
}

5.select

  • select 中只要有一个case能return,则立刻执行。
  • 当如果同一时间有多个case均能return则伪随机方式抽取任意一个执行。
  • 如果没有一个case能return则可以执行”default”块。

6.defer

package main

// 在这个例子中,我们将看到如何使用 Go 协程和通道实现一个工作池 。

import "fmt"


func calc(index string, a, b int) int {
    ret := a + b
    fmt.Println(index, a, b, ret)
    return ret
}
 
func main() {
    a := 1
    b := 2
    defer calc("1", a, calc("10", a, b))
    a = 0
    defer calc("2", a, calc("20", a, b))
    b = 1
}
// 10 1 2 3
// 20 0 2 2
// 2 0 2 2
// 1 1 3 4
// defer是一个栈的结构  前面的就是进来了   数值已经锁定了

7.make

func main() {
    s := make([]int, 5)
    s = append(s, 1, 2, 3)
    fmt.Println(s)
}

[0 0 0 0 0 1 2 3]

s := make([]int, 0)
s = append(s, 1, 2, 3)
fmt.Println(s)

//[1 2 3]

题目

Golang - 面试知识点小结_赵萱婷的博客-CSDN博客

做的

1.格式输出

- %T 类型
- %t 布尔
- %d 10进制整数
- %x 16进制整数
- %f	 浮点数
- %s	 字符串

2.接口

一个类如果实现了一个接口的所有函数,那么这个类就实现了这个接口,即这个类的对象可以使用接口的方法。

3.init

包的init 是初始化函数,在包引入的时候就会调用,一个包可以写多个init函数。

init 函数先于main函数自动执行,不能被其他函数调用;
init 函数没有输入参数、返回值;
每个包可以有多个init函数;
同一个包的init执行顺序,golang没有明确定义,编程时注意不要依赖这个执行顺序,不同包的init函数的执行顺序依照包导入的依赖关系决定执行顺序。

4.执行顺序

5.多参数函数

6.类型转换

类型(变量)

7.引用

获取指针类型的所指向的值, 可以使用: “*”取值符号。

比如 var p *int, 使用p获取p指针,slice、map、chan都是引用类型。

内置函数 new 计算类型大小,为其分配零值内存,返回指针。而 make 会被编译器翻译 成具体的创建函数,由其分配内存和初始化成员结构,返回对象而非指针。

8.切片

9.类成员函数

10.接口

如果两个接口有相同的方法列表,那么他们就是等价的,可以相互赋值。

11.锁

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

12.通道

如果给一个 nil 的 channel 发送数据,会造成永远阻塞

如果从一个 nil 的 channel 中接收数据,也会造成永久爱阻塞

给一个已经关闭的 channel 发送数据, 会引起 pannic

从一个已经关闭的 channel 接收数据, 如果缓冲区中为空,则返回一个零值

无缓冲的 channel是同步的,而有缓冲的channel是非同步的。

13.通道关闭

通道关闭后,如果通道里面仍然有值,就会继续读取,直到没有值,读取到false

给一个关闭的通道传递值会引起panic

如果给一个 nil 的 channel 发送数据,会造成永远阻塞,靠协程进行疏通

如果从一个 nil 的 channel 接收数据,会造成永久阻塞,靠协程进行疏通

14.断言类型

x.(T)被称为断言类型,这里x表示一个接口的类型和T表示一个类型

15.继承

在一个结构体里面加一个架构体,就是继承

16.switch

go 当中switch语句和其他语言类似,只是有一个特殊的地方,switch后面可以不跟表达式

17.make与new

new返回的是指针

make用于slice map channel初始化,返回实例

18异同Printf(),Sprintf(),FprintF()

Printf()格式化输出到屏幕

Sprintf()格式化输出到变量

FprintF()输出到文件

19.数组与切片

数组定长值传递长度也是类型的一部分

切片变长引用传递  make初始化   

20.数组与切片的传递

数组是值传递,只能硬改值,如果是调用函数在函数内改变值的话,就不会达到目的。

切片是引用值,可以硬改,如果调用函数在函数内部的变化,也会反映到函数外部,它意味着[]切片类型默认使用了*切片。

21.runtime.GOMAXPROCS(逻辑CPU数量)

runtime.GOMAXPROCS 的作用是:调整并发的运行性能。 runtime.Gosched()

<1: 不修改任何数值。
=1: 单核心运行。
>1: 多核心运行。

22.defer执行顺序

23.切片

24.异步全局与局部变量

均为输出10, 第一个go func中i是外部for的一个变量,地址不变化。遍历完成后,最终i=10。

故go func执行时,i的值始终是10。

25.接口

结构体的空不是空  不等于nil

package main

import (
	"fmt"
)

type People interface {
}
type Student struct {
}



func live() People {
	// 这个是结构体类型的
	var stu *Student
	return stu

	// 这个是接口类型的
	var stu People
	return stu
}

func main() {
	var a People
	fmt.Println(live())
	fmt.Println(a)

	if a == nil {
		fmt.Println("A")
	} else {
		fmt.Println("B")
	}

	if live() == nil {
		fmt.Println("C")
	} else {
		fmt.Println("D")
	}

	b:=live()
	if b == nil {
		fmt.Println("E")
	} else {
		fmt.Println("F")
	}
}
// <nil>
// <nil>
// A
// D
// F

17.创建

slice chanel map在声明类型之后,还要进行make 

var与:矛盾,有了var就不需要:  有了冒号就不需要var了

array  make([长度]类型)                         赋值  a[1] 或者{}

slice  make([]类型,长度,容量)           赋值  a[1]或者{}

map  make(map[类型]类型)                   赋值  mapp[键值]=值

channel  make(chan 类型)                     赋值  ch<-值

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值